撤销 system_variables_admin 权限后 set global 仍可执行,因该权限仅控制部分动态全局变量修改,其他权限(如 connection_admin、super)或会话级操作仍可绕过;且权限撤销不重置已生效的变量值。

撤销 SYSTEM_VARIABLES_ADMIN 权限后为什么 SET GLOBAL 仍能执行?
因为 SYSTEM_VARIABLES_ADMIN 不是执行 SET GLOBAL 的唯一前提——它只控制「修改动态全局变量」的权限,但某些变量(如 max_connections)还依赖 CONNECTION_ADMIN 或 SUPER(旧版本),而部分变量(如 sql_mode)甚至允许会话级修改绕过全局权限检查。更关键的是:MySQL 不会自动清理已通过 SET GLOBAL 修改过的变量值,撤销权限只是阻止后续修改,历史变更依然生效。
如何确认哪些全局变量已被手动修改过?
MySQL 没有内置日志记录谁、何时改了哪个 GLOBAL 变量,但可通过比对当前值与编译默认值或配置文件值来识别「非默认」状态:
SELECT VARIABLE_NAME, VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME IN ('max_connections', 'wait_timeout', 'innodb_buffer_pool_size');- 对比
mysqld --verbose --help | grep -A 1 "Default options"输出的默认值(需在 mysqld 未运行时执行) - 检查
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf中显式配置的变量——这些优先级高于编译默认值,但低于运行时SET GLOBAL
真正“清理”过期修改:必须重启 + 配置文件归位
运行时 SET GLOBAL 的修改仅驻留在内存,无法通过 SQL “回滚”到原始默认值;唯一可靠方式是让 mysqld 启动时按预期加载配置:
- 删掉所有
SET GLOBAL xxx = yyy;对应的手动设置(尤其是写入my.cnf的临时调试项) - 确保
my.cnf中没有覆盖默认行为的[mysqld]下变量(例如删掉max_connections = 500这类行) - 执行
sudo systemctl restart mysql(或mysqld_safe --defaults-file=/etc/my.cnf &) - 重启后验证:
SELECT @@global.max_connections;应返回编译默认值(如 151)而非上次 SET 的值
权限撤销后还需检查用户是否残留其他高危权限
DROP ROLE 或 REVOKE SYSTEM_VARIABLES_ADMIN ON *.* FROM 'user'@'%' 成功不代表安全收口——很多 DBA 忘记连带清理:
-
REVOKE SUPER ON *.* FROM 'user'@'%'(SUPER在 8.0.12+ 已拆分为细粒度权限,但旧账号可能仍持有) -
REVOKE CONNECTION_ADMIN, PERSIST_ROLES_ADMIN ON *.* FROM 'user'@'%'(这两个权限也能间接影响变量行为) - 检查
SELECT * FROM mysql.role_edges WHERE TO_HOST = '%';确认没通过角色继承获得隐式权限
权限变更后务必执行 FLUSH PRIVILEGES;,否则部分变更不会立即生效。
变量值不随权限撤销而重置,这是最容易被忽略的设计事实——以为 revoke 就万事大吉,结果线上还跑着半年前某次调试留下的 SET GLOBAL innodb_log_file_size = 2G,而磁盘早已告警。











