只靠read_only=on不够,必须同时启用super_read_only=on并回收super权限,否则root等高权限用户仍可删表写入;这是mysql设计行为,因read_only默认仅限制非super用户,而root等自带super权限可绕过;真正生效需在[mysqld]段按序配置read_only=on和super_read_only=on(不可颠倒、不可写错节或值格式),重启mysqld,再用业务账号实测insert应报error 1290。

只靠 read_only = ON 不够,必须同时启用 super_read_only = ON 并回收高权限账号的 SUPER 权限,否则 root 或运维账号仍能删表、写数据。
为什么 read_only = ON 后 root 还能删表?
这是 MySQL 的设计行为,不是配置失败。read_only 默认只限制非 SUPER 权限用户。root、DBA 账号、监控脚本常用账号通常自带 SUPER,可直接绕过该限制。
- 执行
SET GLOBAL read_only = ON后,用root@localhost登录仍能执行DROP TABLE - 监控脚本用高权限账号连从库探活,顺手执行
INSERT INTO health_check VALUES (NOW()),污染数据 -
SHOW VARIABLES LIKE 'read_only'返回ON,但实际没拦住写操作
如何让只读真正生效(持久 + 全局锁死)
两个变量有依赖关系,且都必须全局生效、持久化,否则重启即失效:
- 在
my.cnf或mysqld.cnf的[mysqld]段下,**顺序不能颠倒**地写入:read_only = ON<br>super_read_only = ON
- 绝对不要放在
[client]或[mysql]节里——MySQL 会静默忽略 - 不要写成
read_only = 1或read_only = true,MySQL 只认ON/OFF(大小写不敏感,但推荐大写) - MySQL 8.0.22+ 可改用
SET PERSIST super_read_only = ON,自动写入mysqld-auto.cnf,适合容器或云环境 - 配置后必须
systemctl restart mysqld,mysqladmin reload不生效
哪些写操作 super_read_only 也拦不住?
即使 super_read_only = ON 开启,以下操作仍可能触发隐式写入,破坏只读语义:
-
FLUSH LOGS、RESET MASTER:不改业务表,但破坏复制一致性 - 创建或删除临时表:
CREATE TEMPORARY TABLE不受限制 - 修改系统表(如
mysql.user),尤其当账号有UPDATE权限时 - 调用含写逻辑的存储函数(函数里有
INSERT且未加READS SQL DATA限定)
所以光靠变量不够,还得配合最小权限原则:从库账号只给 SELECT、REPLICATION CLIENT、PROCESS,砍掉所有 DML/DCL 权限。
怎么验证只读是否真生效?
别只信 SHOW VARIABLES——它只反映变量值,不反映权限是否卡死。
- 用实际业务账号登录,执行:
INSERT INTO test_table VALUES (1)—— 应报错ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement - 检查当前连接权限:
SELECT CURRENT_USER(), USER()+SHOW GRANTS FOR CURRENT_USER(),确认无SUPER或SYSTEM_VARIABLES_ADMIN - 已存在的长连接不受新变量影响,需主动断开重连或等其自然退出
最易被忽略的是:主从切换后从库没自动恢复 super_read_only = ON,导致后续写入污染数据;若用了 MGR 或 GTID 自动故障转移,要额外确认该变量是否被覆盖或重置。











