MySQL中不存在“权限碎片”概念,它实为冗余或过期授权记录的误称;真正需处理的是跨库/跨用户重复授权、悬空权限及主从不一致等问题,应通过REVOKE、DROP USER和FLUSH PRIVILEGES安全清理。

mysql 没有“权限碎片”这个概念——你查不到任何官方文档、错误日志或系统表里出现 privilege_fragmentation、grant_fragment 这类字段或术语。所谓“权限碎片”,是误把「冗余、过期、重复、跨库/跨用户重叠的授权记录」当成类似表空间碎片的问题来理解,但二者原理、影响和处理方式完全不同。
为什么 SHOW GRANTS 会返回一堆重复或看似“残留”的权限?
MySQL 的权限模型基于 mysql.user、mysql.db、mysql.tables_priv 等系统表,每条 GRANT 语句都会写入对应行。问题不在于“物理存储碎片”,而在于:
- 同一用户对同一数据库反复执行
GRANT,会新增记录而非覆盖(尤其在旧版本或未用WITH GRANT OPTION控制时) - 账户被
DROP USER后,若未显式FLUSH PRIVILEGES或 mysqld 未重启,缓存中可能残留旧权限判断逻辑(实际已失效) - 使用通配符授权(如
'db_%'.*)后删库,权限记录仍留在mysql.db表中,变成“悬空授权” - 复制环境里从库没同步
GRANT或REVOKE,导致主从权限不一致,看起来像“残留”
这些不是磁盘空间浪费,而是权限策略混乱,直接后果是:最小权限原则失效、审计困难、REVOKE 失败、甚至意外越权。
如何安全识别和清理过期/冗余权限记录?
别直接删 mysql.* 表——MySQL 5.7+ 启用 read_only=ON 时会拒绝写入;8.0+ 更强制要求通过 REVOKE 或 DROP USER 修改权限。
正确路径是:
-
先导出当前所有显式授权:
mysqldump --no-create-info --skip-extended-insert -u root -p mysql user db tables_priv columns_priv procs_priv proxies_priv > grants_backup.sql
-
查出明显过期的授权(例如绑定已删库、匹配不存在用户的记录):
SELECT User, Host, Db FROM mysql.db WHERE Db NOT IN (SELECT SCHEMA_NAME FROM information_schema.SCHEMATA) AND Db != '';
SELECT User, Host FROM mysql.user WHERE User NOT IN (SELECT DISTINCT User FROM mysql.db UNION SELECT DISTINCT User FROM mysql.tables_priv);
-
逐条用 REVOKE 清理,而非 DELETE 表:
REVOKE ALL PRIVILEGES ON `db_old`.* FROM 'app_user'@'%';
DROP USER IF EXISTS 'legacy_script'@'10.0.2.%';
-
清理后必须执行:
FLUSH PRIVILEGES;
注意:FLUSH PRIVILEGES 不是“刷新缓存”那么简单——它会重新加载整个权限表到内存,是清理生效的必要步骤。
哪些操作看似“清理权限”实则危险?
直接
DELETE FROM mysql.user WHERE User = 'xxx';:
MySQL 8.0+ 会报错ERROR 1396 (HY000): Operation DROP USER failed,因内部校验失败;即使 5.7 成功,也会导致mysql.session、mysql.sys等系统账户异常。用
mysqldump导出再导入mysql库:
可能覆盖root密码哈希、丢失authentication_string字段格式,导致无法登录。在主从架构中只在主库
REVOKE,却不检查从库是否同步:
从库权限表不会自动更新,需确认replicate_wild_ignore_table未过滤mysql.%,且 binlog_format = ROW(否则GRANT不写 binlog)。
真正需要警惕的,从来不是“权限碎片”,而是权限变更没走流程、没留记录、没验证效果。一次 REVOKE 执行后不 SHOW GRANTS 确认,比任何“碎片”都容易引发事故。


















