mysql权限分层叠加,user表仅存全局权限快照;实际生效需按user→db→tables_priv→columns_priv顺序逐层匹配,取交集而非简单叠加,高阶权限覆盖低阶限制。

MySQL user 表字段和权限实际生效逻辑不匹配
直接查 mysql.user 表看到的 Select_priv、Insert_priv 等字段值,只是「全局级别权限」的快照,并不反映用户真实拥有的全部权限。MySQL 权限是分层叠加的:列级 SHOW GRANTS 显示的是最终合并后的有效权限集合。
比如你执行过 GRANT SELECT ON mydb.users TO 'u1'@'%';,这个权限存在 mysql.tables_priv 或 mysql.db 表里,但 mysql.user 表里 Select_priv 仍为 N —— 这完全正常,不是数据损坏或同步失败。
-
mysql.user只存 host+user 组合的全局权限(如CREATE DATABASE、SHUTDOWN),以及认证信息 - 数据库级权限存在
mysql.db表,表级在mysql.tables_priv,列级在mysql.columns_priv -
SHOW GRANTS FOR 'u1'@'%'会自动 JOIN 所有权限表,汇总出当前生效的完整授权语句
为什么 FLUSH PRIVILEGES 后 user 表没变,但权限却生效了
FLUSH PRIVILEGES 的作用是把磁盘上权限表(mysql.*)重新加载进内存缓存,但它不修改任何字段值 —— 字段本来就是对的,只是 MySQL 服务端在连接认证和语句执行时,按优先级逐层检查这些表,而不是只看 mysql.user。
常见误解是以为改了 mysql.user.Host 就等于开放远程访问,其实还必须满足:该行 Host 匹配客户端 IP、对应权限字段(如 Select_priv)为 Y、且没有更高优先级的拒绝规则(如 mysql.proxies_priv 中的限制)。
- 手动 UPDATE
mysql.user后必须FLUSH PRIVILEGES,否则内存缓存仍是旧值 - 用
GRANT语句修改权限时,MySQL 自动更新对应表并刷新内存,无需手动FLUSH -
SELECT * FROM mysql.user WHERE User='u1'\G查到的authentication_string是密码哈希,和权限无关,别把它和权限字段混淆
SHOW GRANTS 显示 ALL PRIVILEGES,但实际执行 INSERT 却报 Access denied
这通常不是权限显示错误,而是权限作用范围不匹配。例如:
- 用户被授予
ALL PRIVILEGES ON *.*,但连接时指定了-D otherdb,而otherdb并不存在,MySQL 会拒绝操作(哪怕权限全开) - 用户有
INSERT权限,但目标表启用了SQL_MODE=STRICT_TRANS_TABLES,某字段 NOT NULL 且未提供值,报错看起来像权限问题,实为约束拦截 - 权限中
@'%'不等价于@'localhost'—— Linux 下 Unix socket 连接默认走localhost,而%不匹配localhost,必须显式加'u1'@'localhost'授权
验证方法:用 SELECT CURRENT_USER(), USER(); 确认实际匹配的账号,再查对应权限:SHOW GRANTS FOR CURRENT_USER();
排查权限不一致的最小验证步骤
别先翻源码或怀疑 MySQL Bug,按顺序做这四件事就能定位:
- 确认连接使用的账号:
SELECT USER(), CURRENT_USER();—— 注意二者区别 - 查该账号完整权限:
SHOW GRANTS FOR CURRENT_USER();(不是USER()) - 查权限存储位置:
SELECT Host,Db,Table_name,Column_name,Select_priv,Insert_priv FROM mysql.tables_priv WHERE User='u1';(同理可查db、columns_priv) - 模拟操作验证:
SELECT COUNT(*) FROM information_schema.role_table_grants WHERE grantee="'u1'@'%';(MySQL 8.0+ 支持角色,可能引入间接授权)
真正容易被忽略的点是:MySQL 在权限检查时,会按 user → db → tables_priv → columns_priv 顺序逐层匹配,只要某一层显式拒绝(Deny),就立即终止;而 SHOW GRANTS 只展示「授予」记录,不体现隐式拒绝或 host 匹配失败这类运行时决策。











