仅撤销system_variables_admin无法彻底阻止set global,因connection_admin、super、session_variables_admin等权限可绕过,且角色继承、配置文件及mysqld-auto.cnf中的持久化设置仍生效。

仅撤销 SYSTEM_VARIABLES_ADMIN 权限无法彻底阻止用户修改全局变量——MySQL 8.0+ 中存在多个可绕过该限制的权限路径,必须一并清理。
为什么 REVOKE SYSTEM_VARIABLES_ADMIN 后还能执行 SET GLOBAL
常见现象是:执行了 REVOKE SYSTEM_VARIABLES_ADMIN ON *.* FROM 'user'@'host';,但用户仍能成功运行 SET GLOBAL wait_timeout = 600。这不是权限没生效,而是以下任一情况在起作用:
-
CONNECTION_ADMIN权限隐式包含变量修改能力,且优先级高于SYSTEM_VARIABLES_ADMIN撤销结果 - 用户仍持有
SUPER权限(尤其旧账号未显式回收),该权限在 8.0.12+ 虽已废弃但依然有效 -
SESSION_VARIABLES_ADMIN允许执行SET PERSIST,而该语句会持久化写入mysqld-auto.cnf,重启后自动加载为全局值,效果等同于SET GLOBAL - 用户通过角色(如
mysql.session)间接继承了上述任一权限,SHOW GRANTS不显示角色内嵌权限
如何查清用户真实拥有的变量相关权限
别信你“记得”授了什么,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';,确认输出里没有SYSTEM_VARIABLES_ADMIN、SESSION_VARIABLES_ADMIN或CONNECTION_ADMIN - 查是否属于高危内置角色:
SELECT * FROM mysql.role_edges WHERE TO_HOST = 'host' AND TO_USER = 'user';
特别注意:如果看到 GRANT ... ON *.* TO 'user'@'host' WITH ADMIN OPTION,说明该用户还能把权限再授给他人,必须同步处理。
精准回收权限的完整操作清单
按顺序执行,缺一不可:
- 撤销核心权限:
REVOKE SYSTEM_VARIABLES_ADMIN, SESSION_VARIABLES_ADMIN, CONNECTION_ADMIN, PERSIST_RO_VARIABLES_ADMIN ON *.* FROM 'user'@'host'; - 清理遗留
SUPER:REVOKE SUPER ON *.* FROM 'user'@'host';(即使提示 deprecated,也必须执行) - 刷新生效:
FLUSH PRIVILEGES;(动态权限撤销后必须显式刷新) - 验证是否残留:
SELECT * FROM performance_schema.role_assignments WHERE ROLE = 'user'@'host';,空结果才表示无角色继承
注意:host 必须与用户实际连接时的 host 完全一致(如 '10.20.30.5' ≠ '%'),否则权限不匹配,撤销无效。
撤销后仍需警惕的“非权限”风险点
权限回收只管“能不能发 SET 请求”,不管“变量值本身是否已被改过”:
- 已通过
SET GLOBAL修改的变量仍在内存中生效,重启前不会恢复默认值 -
SET PERSIST写入的mysqld-auto.cnf文件若未被清理,下次启动仍会加载——需手动删或注释该文件中对应行 - 某些变量(如
sql_mode)允许会话级设置绕过全局权限检查,SET SESSION sql_mode = 'STRICT_TRANS_TABLES'无需任何特殊权限 - 配置文件(
/etc/my.cnf)中硬编码的变量值,优先级高于运行时设置,权限控制不了它
真正干净的收口,是权限回收 + 配置文件归位 + 实例重启三者缺一不可。











