mysql 8.0 中不存在 set instance read_only 语法,正确命令是 set global read_only = on/off 和 set global super_read_only = on/off;仅设 read_only 不足,因 super 用户(如 root)仍可写入,必须两者同步开关以确保主备切换安全。

SET INSTANCE READ_ONLY 在 MySQL 8.0 中并不存在 —— 这是个常见误解。MySQL 8.0 没有 SET INSTANCE READ_ONLY 语法,真正可用的是 SET GLOBAL read_only = {ON|OFF} 和 SET GLOBAL super_read_only = {ON|OFF}。强行使用不存在的语句会直接报错:ERROR 1193 (HY000): Unknown system variable 'INSTANCE'。
下面直奔实操重点,聚焦主备切换中只读控制的真实用法和关键细节。
为什么必须同时设 read_only 和 super_read_only
仅开 read_only = ON 不够安全:它对普通用户生效,但对拥有 SUPER 权限的账号(比如 root、复制线程)完全无效。这意味着:
- 运维人员仍可能用 root 执行
INSERT/UPDATE/DELETE - 应用若误配了高权限账号,写操作照常发生
- 主备切换时若漏掉
super_read_only,极易引发双写
所以标准动作是两者同步开关:
SET GLOBAL read_only = ON; SET GLOBAL super_read_only = ON;
反之,新主库启用前必须都关掉:
SET GLOBAL read_only = OFF; SET GLOBAL super_read_only = OFF;
切换前必须确认 Seconds_Behind_Master = 0
只读不是万能锁,它不阻塞复制线程,但如果你在从库还有延迟时就切走流量,会导致数据丢失。关键检查项:
- 执行
SHOW SLAVE STATUS\G,确认Slave_IO_Running: Yes且Slave_SQL_Running: Yes -
Seconds_Behind_Master必须为0(注意:该值可能短暂抖动,建议连续查 2–3 次) - 更可靠的方式是比对
Exec_Master_Log_Pos和主库当前SHOW MASTER STATUS的Position是否一致
FLUSH TABLES WITH READ LOCK 在 8.0 主备切换中已不推荐
这个命令会全局阻塞所有 DML 和 DDL,但它和复制线程冲突,容易导致:
- 复制 SQL 线程卡在
Waiting for table metadata lock - 主库连接堆积,业务超时
- 在 GTID 模式下甚至可能破坏事务连续性
现代主备切换应依赖 read_only + super_read_only 组合,配合应用层灰度切流,而非强锁表。只有在极少数需绝对一致性保障(如金融核心账务库停机维护)时才考虑它,且必须搭配 mysqladmin kill 清理活跃连接。
切换后务必验证角色状态与权限继承
新主库启用写入后,容易忽略两个隐性问题:
- 原主库切为从库时,若未显式执行
RESET SLAVE ALL,残留的master.info可能导致下次启动自动重连旧主,引发循环复制 - 新主库上新建用户或授权,不会自动同步到原主库(除非开启
binlog_format = ROW且复制过滤规则允许),需人工补全或通过工具同步 -
read_only是动态变量,重启后失效;如需持久化,必须写入配置文件中的[mysqld]段落:read_only = ON、super_read_only = ON
SELECT @@read_only, @@super_read_only 验证值是否真为 0。看似简单,却是一次切换成败的最终确认点。











