MySQL 中权限是按层级叠加的,不是继承
MySQL 没有传统意义上的“权限继承”——比如给
db1.*授予
SELECT,不会自动让
db1.table1获得额外权限;它只是把权限记录在
mysql.db表里,作用范围更窄的权限(如表级、列级)会覆盖更宽泛的同名权限。真正起作用的是「匹配优先级」:MySQL 在验证权限时,按
host, user, db, table_name, column_name从左到右逐级匹配,越具体的记录优先级越高。 全局权限(
GRANT ... ON *.*)写入
mysql.user,优先级最低 数据库级(
ON db1.*)写入
mysql.db,优先级中等 表级(
ON db1.t1)写入
mysql.tables_priv,优先级更高 列级(
ON db1.t1(col1))写入
mysql.columns_priv,优先级最高
权限冲突时,MySQL 怎么决定用哪条记录?
当用户执行
SELECT col1 FROM db1.t1,MySQL 会同时查多张权限表,并取各层级中「匹配且启用」的最高优先级记录。关键点在于:不是“叠加”,而是“取最大有效权限”。例如: 用户
'u1'@'localhost'在
mysql.user有
SELECT全局权限 → 允许查所有库 同一用户在
mysql.db对
db1显式
DENY SELECT(通过
GRANT USAGE+ 单独
REVOKE实现)→ 实际拒绝查
db1再在
mysql.tables_priv对
db1.t1单独
GRANT SELECT→ 此时仅对
t1恢复可查
最终效果:查
db1.t2报错,查
db1.t1成功——因为表级权限覆盖了库级
DENY。
REVOKE 不一定能撤销你认为的权限
REVOKE只能撤销「当前作用域内显式授予的权限」,无法影响更高或更低层级的权限记录。常见误操作: 在
db1.*上
GRANT SELECT,然后在
db1.t1上
REVOKE SELECT→ 有效,
t1权限被清除 在
*.*上
GRANT SELECT,然后在
db1.*上
REVOKE SELECT→ 无效!因为全局权限仍存在,用户依然能查
db1想彻底禁用某用户对某个库的访问,必须确保:全局无权限 + 库级无权限 + 表级/列级也无残留记录
检查方式:
SELECT host,user,db,table_name,column_name,Select_priv FROM mysql.db WHERE user='u1' AND db='db1'; SELECT host,user,db,table_name,column_name,Select_priv FROM mysql.tables_priv WHERE user='u1' AND db='db1';
FLUSH PRIVILEGES 不是万能刷新开关
手动修改
mysql.*系统表后,必须执行
FLUSH PRIVILEGES才能让内存缓存更新;但用
GRANT/
REVOKE命令操作时,MySQL 自动完成持久化和加载,此时再执行
FLUSH PRIVILEGES是冗余的,甚至可能掩盖权限未生效的真实原因(比如忘记
GRANT后的
IDENTIFIED BY密码不匹配)。 只在直接
INSERT/UPDATE系统表后才需要
FLUSH PRIVILEGES使用
GRANT后权限立即生效(连接重连后可见),无需刷新 如果
GRANT后权限不生效,先确认
user和
host是否完全匹配(注意
'u1'@'%'和
'u1'@'localhost'是两个不同账户)
权限生效依赖于连接时认证的
user@host组合,这个组合一旦建立就不会再动态切换权限上下文——改完权限后,已有连接不会自动更新权限,必须断开重连。
