必须同时启用 super_read_only = on 才算真正锁死写入,因为 read_only = on 仅限制无 super 权限用户,而 root 等高权限账号仍可执行 drop table 等操作。

只开 read_only = ON 不防 root,必须同时启用 super_read_only = ON 才算真正锁死写入。
为什么 read_only = ON 后 root 还能删表?
这是 MySQL 的设计行为,不是配置失败。read_only 本意是“防手滑”,只拦截没有 SUPER 权限的用户。root、DBA 账号、监控脚本常用账号默认带 SUPER,所以 DROP TABLE、INSERT INTO mysql.user、ANALYZE TABLE(MySQL 8.0+ 对系统表也生效)全都能成功执行。
常见误判场景:
- 运维用
root@localhost执行了SET GLOBAL read_only = ON,以为万事大吉,结果自己还能清表 - BI 工具或健康检查脚本用高权限账号连从库,顺手
INSERT INTO health_log,污染数据 -
SHOW VARIABLES LIKE 'read_only'返回ON,但业务仍在写入——你查的是变量值,不是权限边界
如何正确启用 super_read_only = ON?
它不是独立开关,和 read_only 有强依赖关系:开启 super_read_only 会自动把 read_only 设为 ON;反过来,read_only = OFF 会强制关掉 super_read_only。顺序和写法错一个,就可能启动失败或无效。
实操要点:
- 配置文件中必须写在
[mysqld]段下,且super_read_only = ON必须放在read_only = ON之后(MySQL 5.7.20+ 支持,低于此版本不识别该变量) - 值只能是
ON或OFF,不能写成1、true、yes—— MySQL 会静默忽略或报错 - MySQL 8.0.22+ 可用
SET PERSIST super_read_only = ON,自动写入mysqld-auto.cnf,适合容器/云环境 - 仅
SET GLOBAL不持久:服务重启后失效,必须配合配置文件或SET PERSIST
启用后哪些操作仍可能“绕过”只读?
super_read_only = ON 能拦住绝大多数写操作,但以下几类例外需额外注意:
-
CREATE TEMPORARY TABLE:临时表不受限制(截至 2026 年 7 月 1 日) -
FLUSH LOGS、RESET MASTER:不改业务表,但破坏复制一致性,建议禁用 - 已存在的长连接:变量只对新连接生效,老连接仍按旧状态运行,需手动 kill 或等其自然断开
- 磁盘满 ≥95%:MySQL 会自动静默置
read_only = ON,错误提示一模一样,但你查配置文件什么都没改——先df -h看/var/lib/mysql所在分区
云数据库(如阿里云 RDS、腾讯云 CDB)怎么配?
这类服务通常屏蔽 SET GLOBAL,也不开放配置文件修改权限。你无法直接执行 SET GLOBAL super_read_only = ON。
必须走控制台或 OpenAPI:
- 路径一般是「参数设置」→ 搜索
read_only或「只读实例开关」 - 部分厂商提供「强制只读」选项,底层实际启用了
super_read_only行为,但对外不暴露变量名 - 如果控制台没对应开关,说明该实例不支持运行时只读控制,只能靠网络层(如代理、防火墙)阻断写流量,或提前回收应用账号的写权限
最易被忽略的是主从切换后的状态残留:原从库升为主库后,super_read_only = ON 不会自动关闭,新主库会变成“假性只读”,所有写请求全部失败——这需要在切换流程中显式加入关闭指令。











