撤销动态权限必须使用REVOKE SYSTEM PRIVILEGE语法,如REVOKE SYSTEM PRIVILEGE SET_USER_ID ON . FROM 'user'@'host';MySQL 8.0.16+才支持,且不能与静态权限混淆,也不支持批量撤销或部分撤销。

撤销动态权限前必须确认 MySQL 版本与权限类型
MySQL 8.0.16+ 才支持动态权限(dynamic privileges),像 SET_USER_ID、SYSTEM_USER、BACKUP_ADMIN 这类权限**不隶属于传统 GRANT 表结构,不能用 REVOKE SELECT ON *.* 这种语法撤销**。执行错误语法会报错:ERROR 3724 (HY000): Cannot revoke dynamic privilege 'SET_USER_ID' using old-style REVOKE。
动态权限和静态权限(如 SELECT、INSERT)是两套独立系统:前者控制服务器级操作能力,后者控制数据访问。混淆二者会导致权限清理失败或误删。
- 检查当前用户拥有的动态权限:
SELECT * FROM information_schema.role_table_grants WHERE grantee = "'user'@'host'" AND is_grantable = 'NO' AND privilege_type LIKE '%_ADMIN%'; - 查看所有可用动态权限:
SELECT * FROM information_schema.applicable_roles;(仅限 8.0.19+)或查官方文档列表 -
SHOW GRANTS FOR 'user'@'host';输出中,动态权限会以WITH GRANT OPTION后的独立行出现,例如:GRANT SET_USER_ID ON *.* TO 'admin'@'%'
用 REVOKE SYSTEM PRIVILEGE 正确撤销 SET_USER_ID
撤销 SET_USER_ID 必须使用带 SYSTEM 关键字的专用语法,且对象范围固定为 *.* —— 不接受数据库名或表名:
REVOKE SYSTEM PRIVILEGE SET_USER_ID ON *.* FROM 'appuser'@'%';
这条命令不会影响该用户的任何数据级权限(如 SELECT ON myapp.*),只移除其切换用户上下文的能力。若用户同时拥有多个动态权限,需逐条撤销:
REVOKE SYSTEM PRIVILEGE BACKUP_ADMIN ON *.* FROM 'backup_user'@'10.%';REVOKE SYSTEM PRIVILEGE CLONE_ADMIN ON *.* FROM 'clone_user'@'localhost';- 不能合并写成
REVOKE SYSTEM PRIVILEGE SET_USER_ID, BACKUP_ADMIN ON *.*...—— MySQL 不支持逗号分隔的动态权限批量撤销
撤销后立即生效,无需 FLUSH PRIVILEGES;但已建立的连接仍保有旧权限,直到重新登录。
常见错误:混淆动态权限与角色、或误删全局静态权限
以下操作看似合理,实则危险或无效:
- 执行
REVOKE SET_USER_ID ON *.* FROM 'u'@'%';→ 报错ERROR 3724,缺SYSTEM PRIVILEGE关键字 - 执行
REVOKE ALL PRIVILEGES ON *.* FROM 'u'@'%';→ 只清静态权限,SET_USER_ID等动态权限完全不受影响 - 把
SET_USER_ID当作角色名尝试REVOKE 'set_user_id_role' FROM 'u'@'%';→ 角色不存在,命令静默失败(MySQL 不校验角色是否存在) - 对未启用 partial_revokes 的实例尝试用部分撤销限制动态权限 → 动态权限不支持 PARTIAL REVOKES,
REVOKE SYSTEM PRIVILEGE ... ON sys.*会直接报错
特别注意:SYSTEM_USER 是隐式授予的默认动态权限(只要用户存在就自动拥有),不能被显式 REVOKE;它只在用户被 DROP USER 时才消失。
验证撤销是否真正生效
不能只看 SHOW GRANTS 输出是否“少了那行”,因为缓存可能延迟。最可靠方式是模拟用户行为:
- 用目标用户连接:
mysql -u appuser -p -hxxx - 执行触发
SET_USER_ID的语句:SELECT USER(), CURRENT_USER(); SET ROLE 'some_role';→ 若返回ERROR 1227 (42000): Access denied; you need (at least one of) the SYSTEM_USER privilege(s) for this operation,说明已成功撤销 - 检查权限视图:
SELECT * FROM performance_schema.role_edges WHERE role = "'appuser'@'%'" AND from_privilege = 'SET_USER_ID';应为空结果集
动态权限撤销没有回滚机制,也没有日志记录到 general_log(除非显式开启 log_statement='all'),操作前务必确认目标用户和主机名拼写完全匹配——'user'@'localhost' 和 'user'@'127.0.0.1' 是两个不同用户。











