根本原因是read_only=ON仅限制非SUPER用户,而root等默认拥有SUPER权限,可绕过该限制;必须同时启用super_read_only=ON、回收SUPER权限并持久化配置,否则只读无效。

MySQL从库设为read_only = ON不能防止root或SUPER权限用户误删,必须配合super_read_only = ON并严格管控账号权限,否则“只读”只是假象。
为什么read_only = ON后还能用root删表?
这是MySQL的设计行为,不是配置失败。read_only默认只限制非SUPER权限用户,而root、运维账号等通常自带SUPER权限,可直接绕过。常见现象包括:
- 执行
SET GLOBAL read_only = ON;后,用root@localhost登录仍能执行DROP TABLE - 监控脚本用高权限账号连从库探活,顺手执行
INSERT INTO health_check VALUES (NOW()),污染数据 -
SHOW VARIABLES LIKE 'read_only';返回ON,但实际没拦住写操作
验证方式不是查变量,而是用业务账号实测:INSERT INTO test VALUES (1);——应报错ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement。
真正生效的配置顺序和位置
super_read_only依赖read_only,且两者都必须全局生效、持久化,否则重启即失效:
- 先在
[mysqld]段下写入:read_only = ON,再写super_read_only = ON(顺序不能颠倒) - 绝对不要放在
[client]或[mysql]节里——MySQL会静默忽略 - 不要写成
read_only = 1或read_only = true,MySQL只认ON/OFF(大小写不敏感,但推荐大写) - 配置后必须
systemctl restart mysqld,mysqladmin reload不生效
MySQL 8.0.22+ 可改用SET PERSIST super_read_only = ON;,自动写入mysqld-auto.cnf,适合容器或云环境。
哪些写操作read_only根本拦不住?
即使super_read_only = ON开启,以下操作仍可能触发隐式写入,破坏只读语义:
-
CREATE TEMPORARY TABLE:不受限制,临时表可被应用逻辑误用为中转写入点 -
FLUSH LOGS、PURGE BINARY LOGS:不改业务表,但影响复制一致性 - 含写逻辑的存储函数:如函数内有
INSERT且未声明READS SQL DATA - 修改系统表:若账号仍有
UPDATE权限,仍可写mysql.user等
所以必须配合最小权限原则:从库账号只授SELECT、REPLICATION CLIENT、PROCESS,显式REVOKE SUPER, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER,并执行FLUSH PRIVILEGES;。
主从切换后只读状态会自动恢复吗?
不会。MySQL不感知角色变更,read_only和super_read_only是静态配置,切换后新主库仍保持只读,导致应用写失败;而原主库若没重配,可能变成可写从库,造成数据漂移。
实操建议:
- 使用MGR或GTID自动故障转移时,必须在切换脚本中加入:
SET GLOBAL super_read_only = OFF;(对新主库)和SET GLOBAL super_read_only = ON;(对新从库) - 避免依赖“从库默认只读”的假设,所有节点都应在部署时统一配置,而非靠角色推导
- 已存在的长连接不受新
read_only设置影响,切换后需主动kill旧连接或等其自然断开
最易被忽略的一点:云数据库(如RDS)常禁用super_read_only动态设置,只能通过控制台开关——此时配置文件写入完全无效,必须查清平台限制再操作。


















