仅执行 set global read_only = on 不足以保障数据迁移安全,因其仅限制非super用户、重启失效,且无法拦截root等高权限账号的写操作,易导致主从不一致。

仅执行 SET GLOBAL read_only = ON 不足以保障数据迁移安全,它只拦普通用户,SUPER 权限账号(如 root)仍可写入,且重启后失效。
为什么 SET GLOBAL read_only = ON 在迁移中常被误用
这个命令是动态设置,生效快但不持久——MySQL 重启后自动还原为 OFF。更关键的是,它默认对拥有 SUPER 权限的账号完全无效。数据迁移期间若运维或监控脚本用 root 连接从库执行 DROP TABLE 或 TRUNCATE,操作会成功,主从数据立刻不一致,且 binlog 不记录,无法回溯。
常见误判点:
- 看到
SELECT @@global.read_only返回1就认为“已锁死”,但没测试 root 账号是否还能写 - 迁移前只设了
read_only,忘了super_read_only,结果迁移脚本用高权限账号清空了临时表,连带删了业务数据 - 以为
SET GLOBAL后所有连接立即受限,但已存在的活跃事务仍可COMMIT(只禁止新写操作)
SET GLOBAL read_only = ON 的正确使用场景
它适合短时、可控、有明确退出机制的维护窗口,比如配合 FLUSH TABLES WITH READ LOCK 做物理备份,或在确认无 SUPER 用户连接的前提下做小范围验证。
实操要点:
- 必须先确认当前会话有
SUPER权限,否则报错ERROR 1227 (42000): Access denied - 执行后立刻检查:用业务账号连上执行
INSERT INTO t VALUES(1),应报ERROR 1290 (HY000);再用 root 执行同样语句——若成功,说明super_read_only没开,不能用于迁移 - 不要单独依赖它:迁移开始前必须同步执行
SET GLOBAL super_read_only = ON(MySQL 5.7.8+) - 迁移结束后,恢复写入需按顺序关闭:
SET GLOBAL super_read_only = OFF→SET GLOBAL read_only = OFF,顺序反了会失败
配置文件里写 read_only = ON 比 SET GLOBAL 更可靠
临时命令易遗漏、易遗忘、重启即丢。生产环境的数据迁移必须靠配置固化。
注意事项:
- 必须写在
[mysqld]段下,写到[client]或其他节会被忽略 - 值只能是
ON或OFF(不接受1、true、yes),大小写不敏感但推荐大写 - 要真正全局只读,
super_read_only = ON必须写在read_only = ON之后,MySQL 启动时会校验顺序 - 改完配置必须
systemctl restart mysqld,mysqladmin reload不生效
迁移时比只读参数更易被忽略的三个点
只读开关只是防线之一。以下三点不处理,照样可能写坏从库:
- 主库同步了
mysql.user表,导致从库也有带SUPER的账号——必须在从库上REVOKE SUPER ON *.* FROM 'app_user'@'%'并FLUSH PRIVILEGES - 应用连接串里带
autoReconnect=true或连接池未清理旧连接,迁移中部分请求仍打到旧的非只读连接上 -
ALTER DATABASE `backup_db` READ ONLY = 1(MySQL 8.0.22+)虽能单库锁定,但它不阻止跨库写入(如INSERT INTO backup_db.t1 SELECT * FROM prod_db.t2),这种操作仍需靠实例级只读兜底











