partial revoke 是 mysql 8.0.16+ 引入的权限例外机制,非撤销而是叠加禁止规则;升级后因全局权限默认覆盖系统库,旧账号可能意外获得 mysql/sys 敏感表访问权,违反最小权限原则,需启用 partial_revokes=on 后显式 revoke select on sys.* 等方可限制。

Partial Revoke 是什么,升级后为什么突然需要它?
MySQL 8.0.16+ 的 PARTIAL REVOKES 不是“撤销权限”,而是叠加一层“例外规则”:用户仍有全局 SELECT,但可被明确禁止查 sys 或 mysql 库。升级后(尤其从 5.7 → 8.0),很多旧账号因未显式限制系统库访问,会意外获得对 mysql.user、sys.schema_table_statistics 等敏感表的读取能力——这违反最小权限原则,也触发合规审计告警。
常见现象:SHOW GRANTS FOR 'app'@'%' 显示用户有 SELECT ON *.*,但你发现它能 SELECT * FROM mysql.user,而你根本没授过这条权限。根源是:MySQL 8.0 默认允许全局权限覆盖系统库(除非显式限制)。
启用 Partial Revoke 前必须做三件事
不设 partial_revokes=ON 就执行 REVOKE SELECT ON sys.* FROM ...,直接报错 ERROR 3789 (HY000)。必须按顺序操作:
- 运行
SET PERSIST partial_revokes = ON;(不是SET GLOBAL,否则重启失效) - 确认生效:
SELECT @@global.partial_revokes;返回1 - 检查目标数据库是否存在且非
INFORMATION_SCHEMA(该库禁止部分撤销,硬写会报错)
给迁移后的用户加“禁止查 sys/mysql”的具体命令
语法很关键:必须是 REVOKE privilege_type ON db_name.* FROM 'user'@'host',不是 ON *.*,也不是 ON db_name.table_name。
实操示例:
REVOKE SELECT ON sys.* FROM 'app'@'%'; REVOKE SELECT ON mysql.* FROM 'app'@'%'; REVOKE SHOW DATABASES ON *.* FROM 'app'@'%';
注意:
-
SHOW DATABASES是全局权限,但也能被部分撤销(需先启用partial_revokes) - 撤销后立刻生效,无需
FLUSH PRIVILEGES - 执行
SHOW GRANTS FOR 'app'@'%'会看到新增的REVOKE SELECT ON `sys`.* FROM `app`@`%`行 - 用户仍能查业务库(如
myapp.users),仅系统库被拦截
迁移时最容易踩的坑:已有部分撤销就不能用传统 REVOKE 清空
如果用户已存在部分撤销规则,再执行 REVOKE ALL PRIVILEGES ON *.* FROM 'app'@'%' 会报错 ERROR 3790 (HY000):“Cannot revoke privileges on *.* because it has partial revokes”。这时必须先清理例外规则:
- 逐条撤销:例如
REVOKE SELECT ON sys.* FROM 'app'@'%' - 不能用通配符:
REVOKE SELECT ON `test_%`.* FROM ...非法,必须指定真实库名 - 角色继承的权限不受影响——
PARTIAL REVOKES只作用于直接授予用户的全局权限,不触碰角色绑定
真正麻烦的是:升级后迁移用户时,若直接导入旧版 GRANT 语句(不含部分撤销),新实例里用户就裸奔了;但若手动补 REVOKE,又得先确认所有用户是否已启用 partial_revokes,漏一个就会留缺口。这个开关状态本身不会随用户导出导入迁移,必须在目标实例上单独设置。











