真正回收用户全部权限需四步:先revoke显式权限,再update mysql.user清管理字段并flush privileges,接着撤销空用户对information_schema等的隐式select权限及解绑角色,最后注意usage无法撤销且活跃连接缓存旧权限。

直接回收 ALL PRIVILEGES 和 GRANT OPTION 不够用
执行 REVOKE ALL PRIVILEGES, GRANT OPTION ON *.* FROM 'user'@'host' 只能撤掉显式授予的全局权限,但无法触达三类残留权限:MySQL 8.0 默认赋予空用户(''@'')对 information_schema 的 SELECT 权限、用户在 mysql.user 表中直接存储的管理权限字段(如 Super_priv、Reload_priv)、以及通过角色继承的权限。这些权限不会出现在 SHOW GRANTS 输出里,却真实生效。
必须手动清理 mysql.user 表里的管理权限字段
全局管理权限(如 SUPER、SHUTDOWN、RELOAD、PROCESS 等)不走 GRANT/REVOKE 流程,而是直存于 mysql.user 表的布尔字段中。想真正剥离,得用 UPDATE:
- 先查目标用户当前状态:
SELECT Host, User, Super_priv, Reload_priv, Shutdown_priv, Process_priv FROM mysql.user WHERE User = 'u1' AND Host = '%'; - 逐项设为
'N':UPDATE mysql.user SET Super_priv = 'N', Reload_priv = 'N', Shutdown_priv = 'N', Process_priv = 'N' WHERE User = 'u1' AND Host = '%'; - 必须执行
FLUSH PRIVILEGES;—— 这次不能省,因为绕过了REVOKE机制
别忘了 PUBLIC 隐式权限和角色绑定
即使清空了用户自身权限,只要没处理底层隐式授权,普通用户仍能查 information_schema,甚至让 EXPLAIN 报错(因元数据不可读)。同时,若该用户绑定了角色(如 db_admin),仅撤显式权限毫无意义。
- 查隐式源:
SELECT Host, Db, Select_priv FROM mysql.db WHERE User = '' AND Host = ''; - 回收默认元数据访问:
REVOKE SELECT ON information_schema.* FROM ''@'';、REVOKE SELECT ON performance_schema.* FROM ''@'';、REVOKE SELECT ON sys.* FROM ''@''; - 查角色绑定:
SELECT FROM_HOST, FROM_USER FROM mysql.role_edges WHERE TO_USER = 'u1' AND TO_HOST = '%'; - 逐个解绑:
REVOKE 'role_name' FROM 'u1'@'%';
回收后最危险的盲区:USAGE 权限和连接残留
USAGE 是空权限,所有用户默认拥有,它允许登录但不做任何操作——但它不会被 REVOKE ALL PRIVILEGES 撤销,也不会被 UPDATE mysql.user 影响。更麻烦的是,已建立的连接会缓存旧权限,直到断开重连。这意味着你执行完所有命令,用 SHOW GRANTS FOR 'u1'@'%' 看起来干净了,但正在运行的应用仍可能以旧权限执行语句。











