新主库事务执行失败的最常见原因是read_only或super_read_only仍为ON;需先执行SET GLOBAL super_read_only = OFF,再执行SET GLOBAL read_only = OFF,并确认两者均返回0。

因为新主库的 read_only 或 super_read_only 仍为 ON,这是最常见、最直接的原因。 它不是权限问题、网络问题或复制中断,而是 MySQL 实例本身拒绝执行任何写操作——哪怕你用 root 登录、语句完全合法,也会报 ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement。
检查 read_only 和 super_read_only 是否启用
切换后第一件事不是查日志、不是看复制状态,而是立刻确认只读开关:
- 执行
SELECT @@read_only;—— 返回1表示开启;返回0说明已关,但别急着松口气 - 必须紧接着执行
SELECT @@super_read_only;—— 如果返回1,它会强制覆盖read_only设置,即使你刚把read_only设为0,写操作依然被拒 - 注意:MySQL 5.7+ 默认在从库启动时自动设
read_only=ON,且某些高可用工具(如 MHA、Orchestrator)切换后不会自动清理super_read_only
临时关闭只读需按顺序执行
不能只关 read_only,必须先解 super_read_only,否则 SET 不生效:
- 先执行
SET GLOBAL super_read_only = OFF;(需要SUPER或SYSTEM_VARIABLES_ADMIN权限) - 再执行
SET GLOBAL read_only = OFF; - 验证:两次
SELECT @@read_only;和SELECT @@super_read_only;都应返回0 - ⚠️ 不要跳过第一步:若
super_read_only=ON,read_only的值在 SHOW VARIABLES 里可能显示为OFF,但实际行为仍是只读
为什么配置文件里没写 read_only 却还是只读?
MySQL 启动时会按固定顺序加载多个配置文件,任何一个里面写了 read_only=1 都会生效:
- 运行
mysql --verbose --help | grep -A 1 'Default options'查看加载顺序,典型路径包括:/etc/my.cnf、/etc/mysql/my.cnf、/usr/local/mysql/etc/my.cnf、~/.my.cnf - 逐个检查这些文件是否存在、是否含
read_only或super_read_only配置项(注意大小写不敏感,也可能是read_only=ON) - 特别留意
~/.my.cnf—— DBA 或自动化脚本有时会把只读配置写进用户级配置,重启后持续生效,且容易被忽略 - 如果确认所有配置文件都没写,那大概率是上一次手动 SET 过但没持久化,重启后恢复默认(从库默认 ON),此时必须动态关 + 修改配置文件双保险
客户端还在连旧主库(DNS/VIP 滞后)
这不是新主库的问题,但现象一模一样:应用发 INSERT,却收到只读错误——因为请求根本没到新主库:
- 检查应用连接串里的 host:是 IP?VIP?还是域名?如果是后者,
dig +short your-db-vip.example.com看解析结果是否已指向新主库 IP - 查应用服务器上的 DNS 缓存:
systemd-resolve --statistics(systemd)或nslookup your-db-vip.example.com多试几次看 TTL 剩余时间 - 登录新主库执行
SHOW PROCESSLIST;,看是否有来自应用服务器的活跃连接;如果没有,而旧主库(现从库)上还有大量写连接,基本可断定是路由未切 - 临时绕过:让应用直连新主库 IP 测试,若 OK,则问题锁定在网络层或客户端缓存
真正麻烦的不是 read_only=ON 本身,而是它常和长事务锁、GTID 断点、客户端连接池老化混在一起。每次切换后,必须按「只读开关 → 连接路由 → 锁状态 → 复制位点」这个顺序快速排查,漏掉任意一环都可能把 5 分钟能解决的问题拖成小时级故障。


















