mysql 8.0+ 必须显式撤销 system_variables_admin、session_variables_admin 和 persist_ro_variables_admin 权限才能限制用户修改对应变量,仅 revoke super 无效;mysql 5.7 中撤销 super 即可阻止 set global。

MySQL 8.0+ 必须显式撤销 SYSTEM_VARIABLES_ADMIN
只 REVOKE SUPER 没用。MySQL 8.0 起,SET GLOBAL 和 SET PERSIST 的权限已拆分为独立权限:SYSTEM_VARIABLES_ADMIN 控制全局变量修改(含持久化),SESSION_VARIABLES_ADMIN 控制 SET SESSION,PERSIST_RO_VARIABLES_ADMIN 单独控制只读变量的持久化写入。
常见错误是执行了 REVOKE SUPER ON *.* FROM 'user'@'host' 就以为万事大吉,但 SHOW GRANTS FOR 'user'@'host' 仍可能显示 GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO ... ——说明细粒度权限还在。
- 禁止改全局变量:
REVOKE SYSTEM_VARIABLES_ADMIN ON *.* FROM 'user'@'host'; - 禁止改会话变量:
REVOKE SESSION_VARIABLES_ADMIN ON *.* FROM 'user'@'host'; - 禁止写
mysqld-auto.cnf(即禁用SET PERSIST):REVOKE PERSIST_RO_VARIABLES_ADMIN ON *.* FROM 'user'@'host'; - 执行后必须
FLUSH PRIVILEGES;,否则权限变更不生效
MySQL 5.7 只撤 SUPER 就够了
在 MySQL 5.7 中,SET GLOBAL 唯一依赖 SUPER 权限。只要用户没有 SUPER,就无法执行 SET GLOBAL sort_buffer_size = 1048576 这类语句,报错为 ERROR 1227 (42501): Access denied; you need (at least one of) the SUPER privilege(s)。
但注意:即使没 SUPER,用户仍可自由修改自己的会话变量(SET SESSION),比如 SET SESSION sql_mode = 'STRICT_TRANS_TABLES' ——这不需要额外权限,也不受限制。
-
REVOKE SUPER ON *.* FROM 'user'@'host';是唯一必要操作 - 无需
FLUSH PRIVILEGES(REVOKE自动生效) - 确认方式:
SHOW GRANTS FOR 'user'@'host';输出里不应再出现SUPER
为什么用户还能改某些变量?检查作用域和只读性
权限控制的是“能否发起 SET GLOBAL 请求”,不是“请求是否成功”。有些变量本身就是只读的(如 innodb_buffer_pool_size 在运行中不可调),有些则依赖引擎状态或配置模式(如 read_only=ON 时,连 SUPER 用户也无法写入)。
更隐蔽的情况是:变量值虽被拒绝修改,但错误信息可能被应用层吞掉,导致你以为“没生效”——实际是权限起了作用,只是失败静默了。
- 执行
SET GLOBAL max_connections = 500;报ERROR 1227→ 权限已生效 - 执行
SET GLOBAL innodb_buffer_pool_size = 2147483648;报ERROR 1238(Variable is a read-only variable)→ 不是权限问题,是变量本身不可动态改 - 执行
SET GLOBAL read_only = OFF;在super_read_only=ON时会失败 → 权限足够,但更高优先级开关阻断了操作
别信 ALL PRIVILEGES,它不包含变量管理权
GRANT ALL PRIVILEGES ON *.* TO 'user'@'host'; 在 MySQL 8.0.16+ 中明确不包含 SYSTEM_VARIABLES_ADMIN、BACKUP_ADMIN 等管理权限。这是故意设计的“最小权限”默认行为,不是遗漏。
很多 DBA 误以为给个 ALL 就能管一切,结果发现 SET PERSIST 依然报错 ERROR 1227,根源就是没单独授这个权限。
- 授予权限必须显式:
GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO 'admin_user'@'192.168.1.%'; - 主机名必须精确匹配连接时的
host字段,'admin_user'@'%'和'admin_user'@'192.168.1.100'是两个不同账号 - 授完权后不用
FLUSH PRIVILEGES,但必须验证:SHOW GRANTS FOR 'admin_user'@'192.168.1.%';
真正容易被忽略的点是:权限判断发生在连接建立后的 SQL 解析阶段,而变量修改失败往往不中断事务、不抛异常到应用日志——你得主动查错误码,或在测试时紧盯 ERROR 1227 是否出现。











