彻底禁止用户执行 set global 需同时撤销 system_variables_admin、session_variables_admin 和 connection_admin 权限,并执行 flush privileges;仅撤 system_variables_admin 不够,因 set persist 可绕过,且需检查角色继承与连接复用风险。

MySQL 8.0+ 中如何彻底禁止用户执行 SET GLOBAL
直接结论:仅靠 REVOKE 掉 SYSTEM_VARIABLES_ADMIN 权限还不够,必须同时禁用 SESSION_VARIABLES_ADMIN(否则可通过 SET PERSIST 绕过),且需确认用户无 CONNECTION_ADMIN(该权限隐含变量修改能力)。
常见错误是只回收 SYSTEM_VARIABLES_ADMIN,结果发现用户仍能用 SET PERSIST sort_buffer_size = 1048576 修改全局参数——因为 PERSIST 属于 SESSION_VARIABLES_ADMIN 范畴。
-
SYSTEM_VARIABLES_ADMIN:控制SET GLOBAL和SELECT @@global.xxx -
SESSION_VARIABLES_ADMIN:控制SET PERSIST、SET PERSIST_ONLY,以及读写performance_schema.variables_info -
CONNECTION_ADMIN:高危权限,隐式包含变量管理能力,务必检查
检查用户当前实际拥有的变量相关权限
别信 GRANT 语句的“表面权限”,MySQL 权限是叠加生效的。一个用户可能通过角色、系统角色(如 mysql.session)、或被授予的高权限账号间接获得变量修改权。
执行以下查询确认真实权限:
SELECT * FROM information_schema.role_table_grants
WHERE grantee = "'your_user'@'host'" AND privilege_type IN ('SYSTEM_VARIABLES_ADMIN', 'SESSION_VARIABLES_ADMIN', 'CONNECTION_ADMIN');
再查直接授权:
SHOW GRANTS FOR 'your_user'@'host';
- 若输出中出现
WITH ADMIN OPTION,说明该用户还能授予权限,风险极高 - 注意
root或mysql.sys等内置账户是否被意外赋予了角色 - MySQL 8.0.16+ 启用
activate_all_roles_on_login=ON时,角色权限会自动激活,需额外排查
安全回收权限的实操步骤(MySQL 8.0.12+)
回收不是简单 REVOKE 就完事,顺序和配套操作影响实效性:
- 先执行:
REVOKE SYSTEM_VARIABLES_ADMIN, SESSION_VARIABLES_ADMIN, CONNECTION_ADMIN ON *.* FROM 'your_user'@'host'; - 再执行:
FLUSH PRIVILEGES;(必须,否则权限缓存不更新) - 验证是否生效:
SELECT @@global.max_connections;应报错Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN privilege(s) for this operation - 如果用户仍能改,立刻检查
SELECT user, host, account_locked FROM mysql.user WHERE user = 'your_user';—— 账户被锁但权限未清空时,某些客户端仍可复用旧连接执行命令
为什么 SET SESSION 不受影响,但也要警惕?
SET SESSION 默认不需要特殊权限(除非修改受保护的 session 变量如 sql_log_bin),所以即使回收全部 global 权限,用户仍可调 sort_buffer_size 或 join_buffer_size 影响单个查询性能。
这不是漏洞,而是设计使然。但若业务要求严格隔离,需配合其他手段:
- 在连接池层(如 ProxySQL、MaxScale)限制允许的
SET语句白名单 - 启用
init_connect配置项,强制重置关键 session 变量(但对 SUPER 用户无效) - 监控
performance_schema.events_statements_history_long,告警异常的SET操作
真正难防的从来不是语法,而是权限继承链和连接复用场景——比如应用用长连接维持 8 小时,你刚 revoke 完权限,它还在用旧上下文执行 SET PERSIST。











