set global read_only=1 对 root 不生效是因为该参数仅限制非 super 权限用户,root 默认拥有 super 权限,故仍可执行写操作;这是设计行为而非 bug。

set global read_only=1 为什么对 root 不生效
MySQL 的 read_only 是个“君子协议”式开关:它只阻止普通用户(非 SUPER 权限)执行写操作,但对拥有 SUPER 权限的账号(比如默认 root)完全无效。你执行 SET GLOBAL read_only = 1 后,用 root 登录照样能 INSERT、UPDATE、DROP——这不是 bug,是设计如此。
实操建议:
- 确认当前用户权限:
SELECT user(), super_priv FROM mysql.user WHERE user=USER(); - 若需让
root也受约束,必须先回收其SUPER权限:REVOKE SUPER ON *.* FROM 'root'@'%'; FLUSH PRIVILEGES;(注意:这会影响备份、复制等依赖 SUPER 的操作) - 更稳妥的做法是创建专用只读账号:
CREATE USER 'ro_app'@'%' IDENTIFIED BY 'xxx'; GRANT SELECT ON *.* TO 'ro_app'@'%';
my.cnf 里配置 read_only=1 启动后仍可写入
配置文件写对了,但 MySQL 没读到,或被运行时覆盖了。常见原因有三类:配置位置错、未重启生效、启动后被动态改回。
实操建议:
- 确认配置写在正确 section 下:
[mysqld]段内,不是[client]或其他段 - 检查实际加载的配置文件路径:
mysqld --verbose --help | grep "Default options",再验证该路径下是否真有read_only=1 - 启动后立刻查状态:
SELECT @@global.read_only;,如果不是 1,说明没加载成功;如果是 1 但之后变成 0,说明被脚本或监控工具重置了(比如某些高可用组件会动态关闭 read_only) - 避免被覆盖:在配置中加
super_read_only=1(MySQL 5.7.8+),它比read_only更严格,且不能被非 SUPER 用户动态关闭
从库开启 read_only 后,SQL 线程写入失败
这是最典型的误用场景:MySQL 从库的 SQL 线程本身需要写数据(回放 relay log),但它默认不具备 SUPER 权限,一旦 read_only=1,它就会卡住,报错 ERROR 1792 (HY000): Cannot execute statement in a READ ONLY transaction。
实操建议:
- 从库必须同时启用
super_read_only=1而非仅read_only=1——因为super_read_only允许 SQL 线程和具有REPLICATION_SLAVE_ADMIN权限的线程绕过限制 - 确保 MySQL 版本 ≥ 5.7.8(
super_read_only在此版本引入) - 检查复制状态:
SHOW SLAVE STATUS\G,重点看Seconds_Behind_Master和SQL_Thread_State;若卡在 “Waiting for master to send event”,大概率是read_only阻断了 SQL 线程 - 临时修复命令(不推荐长期用):
SET GLOBAL super_read_only = 0; START SLAVE; SET GLOBAL super_read_only = 1;
read_only 和 super_read_only 的兼容性与陷阱
这两个参数不是简单叠加关系,行为随版本变化明显。MySQL 8.0.11 之后,read_only 默认为 OFF,而 super_read_only 默认为 ON(仅当 read_only 为 ON 时才生效)。混乱就在这里。
实操建议:
- 不要单独设
read_only=1,务必配套设super_read_only=1,否则权限逻辑不可控 - MySQL 5.7 中,
super_read_only设为 1 后,read_only自动变为 1;但 MySQL 8.0.11+ 反过来:super_read_only仅在read_only=1时起作用 - 检查当前组合状态:
SELECT @@global.read_only, @@global.super_read_only;,理想值应为1,1 - 注意:修改
super_read_only需要SYSTEM_VARIABLES_ADMIN权限(MySQL 8.0+),不是所有 DBA 账号默认都有
真正麻烦的是权限链和版本差异——同一套配置,在 5.7 和 8.0 上表现可能相反;而 super_read_only 的“开关依赖”特性,很容易让人以为设了就万事大吉,结果发现它根本没启动。











