仅撤销 SYSTEM_VARIABLES_ADMIN 权限无法防止误修改,因 CONNECTION_ADMIN、SESSION_VARIABLES_ADMIN、SUPER 及角色继承仍可绕过,须同步回收四类权限并刷新缓存。

仅撤销 SYSTEM_VARIABLES_ADMIN 权限无法防止误修改——MySQL 8.0+ 中,SET GLOBAL 和 SET PERSIST 分属不同权限路径,必须同步清理四类权限并刷新缓存,否则开发人员仍能通过任意一条路径绕过。
为什么撤了 SYSTEM_VARIABLES_ADMIN 还能 SET GLOBAL?
这不是权限没生效,而是用户可能还持有以下任一隐含能力的权限:
-
CONNECTION_ADMIN:该权限隐式包含全局变量修改能力,且优先级高于SYSTEM_VARIABLES_ADMIN撤销结果 -
SESSION_VARIABLES_ADMIN:允许执行SET PERSIST,写入mysqld-auto.cnf,重启后自动加载为全局值 -
SUPER:虽在 8.0.12+ 被标记为 deprecated,但未显式回收就依然有效 - 角色继承:例如用户被赋予了
mysql.session角色,而该角色自带CONNECTION_ADMIN
特别注意:SHOW GRANTS FOR 'user'@'host' 不显示角色内嵌权限,仅靠它判断会漏掉关键风险。
查清用户真实拥有的变量相关权限
别信“记得授了什么”,MySQL 权限是叠加生效的。必须交叉查询系统表确认:
- 查角色授予的权限:
SELECT * FROM information_schema.role_table_grants WHERE grantee = "'user'@'host'" AND privilege_type IN ('SYSTEM_VARIABLES_ADMIN', 'SESSION_VARIABLES_ADMIN', 'CONNECTION_ADMIN'); - 查直接授权:
SHOW GRANTS FOR 'user'@'host';,确认输出里没有上述任一权限 - 查是否属于高危内置角色:
SELECT * FROM mysql.role_edges WHERE TO_HOST = 'host' AND TO_USER = 'user'; - 若看到
WITH ADMIN OPTION,说明该用户还能把权限再授给他人,必须同步处理
精准回收权限的完整操作清单
按顺序执行,缺一不可:
- 先执行:
REVOKE SYSTEM_VARIABLES_ADMIN, SESSION_VARIABLES_ADMIN, CONNECTION_ADMIN, PERSIST_RO_VARIABLES_ADMIN ON *.* FROM 'user'@'host'; - 再执行:
REVOKE SUPER ON *.* FROM 'user'@'host';(即使提示 deprecated,也必须执行) - 刷新生效:
FLUSH PRIVILEGES;(动态权限撤销后必须显式刷新) - 验证是否残留:
SELECT @@global.max_connections;应报错Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN privilege(s)
最容易被忽略的是 host 匹配——如果应用连的是 'dev_app'@'10.20.30.40',而你只撤销了 'dev_app'@'%',那照样能执行。
额外防护:避免开发环境误连生产库改参数
权限回收只是后端防线,前端隔离同样关键:
- 开发终端连接生产库时,强制加
--prompt='PROD> ',让提示符肉眼可辨 - 在
~/.my.cnf的[client]段下配置safe-updates=1,防止无 WHERE 的 UPDATE/DELETE - 禁止代码或配置中硬写 IP 和账号,统一用语义化域名(如
mysql-prod.example.com)+ 环境变量加载 - 生产库账号默认只授
SELECT和极少数白名单UPDATE,禁用DROP、TRUNCATE、ALTER TABLE
真正起效的防护不是靠某一条命令,而是权限清理、角色排查、连接隔离、客户端约束这四层同时咬合——漏掉任何一层,都可能让一次手抖变成事故。


















