mysql权限管理如何实现_mysql权限体系解析

来源:这里教程网 时间:2026-02-28 20:53:11 作者:

MySQL 的权限模型基于「用户+主机+密码」三元组

MySQL 不像 PostgreSQL 那样按数据库用户全局唯一,而是把

'user'@'host'
当作一个独立账号。比如
'app'@'192.168.1.%'
'app'@'localhost'
是两个完全无关的账户,权限需分别授予。常见错误是只给远程 IP 授权却忘了
'localhost'
,导致本地命令行连得上、程序连不上——因为 MySQL 客户端默认用
localhost
连接时走 socket,实际匹配的是
'user'@'localhost'
,而非
'user'@'%'

创建用户必须显式指定 host:

CREATE USER 'dev'@'10.0.2.%' IDENTIFIED BY 'pwd123';

不写 host 默认是
'%',但这是模糊且不安全的,应避免。

GRANT 语句不自动刷新权限,但 FLUSH PRIVILEGES 多数时候没必要

执行

GRANT
CREATE USER
后,权限已写入
mysql.user
等系统表,并由服务端即时加载——不需要手动
FLUSH PRIVILEGES
。只有在直接 UPDATE 系统表(如绕过 GRANT 修改
mysql.db
)后才需要刷新。

✅ 正确做法:
GRANT SELECT ON sales.* TO 'report'@'%';
❌ 多余操作:
GRANT ...; FLUSH PRIVILEGES;
⚠️ 真要用到 FLUSH:仅当你用
UPDATE mysql.user SET authentication_string=...
这类直改系统表的操作之后

权限层级混乱是线上事故高发区

MySQL 权限分五层:全局(

*
)、库级(
db.*
)、表级(
db.tbl
)、列级(
db.tbl(col1)
)、存储过程级。低层级权限不会继承高层级,且**同名账号在不同层级的权限是叠加的**。

典型陷阱:

'api'@'%' 
授予
SELECT
shop.users
表,又单独给
'api'@'%' 
授予
INSERT
shop.orders
表——这没问题;
但如果误对
'api'@'%' 
执行了
REVOKE ALL ON *.* FROM 'api'@'%'
,会清掉所有全局和库级权限,但**表级、列级权限不受影响**,导致行为不可预测;
更隐蔽的是:同一账号在
mysql.db
mysql.tables_priv
中都有记录时,MySQL 按“最具体匹配”生效,调试需查
SHOW GRANTS FOR 'user'@'host';
而非只看某张表

生产环境禁用 IDENTIFIED WITH caching_sha2_password 的匿名访问风险

MySQL 8.0 默认认证插件是

caching_sha2_password
,它要求 TLS 或安全连接,否则客户端可能静默降级失败。而很多旧脚本或中间件(如某些版本的 Django ORM)未显式配置
ssl_disabled = False
,连上去就报
Access denied for user
,实际是握手阶段被拒绝,不是权限问题。

解决方式(选其一):

创建用户时强制指定旧插件:
CREATE USER 'svc'@'%' IDENTIFIED WITH mysql_native_password BY 'xxx';
或在服务端配置
default_authentication_plugin=mysql_native_password
(需重启)
或确保客户端连接串含
?ssl-mode=DISABLED
(仅测试环境,勿用于生产)

权限本身没毛病,但认证链断了,

SHOW GRANTS
看起来一切正常,排查时容易卡在权限逻辑里绕圈子。

相关推荐