必须确认seconds_behind_master为0且io/sql线程均运行中,再比对read_master_log_pos与主库position完全一致;旧主设read_only=on并验证生效;原从库执行stop slave、reset slave all、read_only=off;其他从库用新主show master status的位点执行change master to并start slave。

确认从库已追平主库 binlog 位置
手动切换前最常被跳过的一步:不检查 Seconds_Behind_Master 是否为 0,直接切就丢数据。它不是“看起来没延迟”,而是必须确认 IO 线程和 SQL 线程都已停稳、位点完全一致。
- 在原从库上执行
SHOW SLAVE STATUS\G,重点看:Slave_IO_Running: Yes、Slave_SQL_Running: Yes、Seconds_Behind_Master: 0 - 再比对
Master_Host对应的原主库上的SHOW MASTER STATUS输出,确保从库的Read_Master_Log_Pos和原主库的Position完全相等 - 如果
Seconds_Behind_Master是NULL,说明 SQL 线程已停止(比如刚执行过STOP SLAVE),此时必须先START SLAVE等追平,再STOP SLAVE
停掉旧主库写入并设为只读
切主不是“让新主上线”,而是“让旧主下线”。很多故障转移失败,是因为应用还在往旧主写,导致双写冲突或数据分裂。
- 在原主库上执行:
SET GLOBAL read_only = ON;(注意:需有SUPER权限) - 立刻验证:
SELECT @@read_only;返回1才算生效 - 更保险的做法是同时执行:
FLUSH TABLES WITH READ LOCK;—— 但该命令会阻塞所有 DML 和部分 DDL,仅建议在低峰期、且已确认无长事务时使用 - 别漏掉应用层:检查连接池配置、DNS 缓存、负载均衡器后端健康检查,确保流量不再打到旧主库 IP
将原从库提升为新主库
这步看似只是改个角色,实际核心是重置复制坐标——否则它仍认为自己是“从”,下次重启可能自动重连旧主、覆盖已有数据。
- 在原从库上执行:
STOP SLAVE;(确保复制彻底停止) - 执行:
RESET SLAVE ALL;(ALL很关键,清除master.info文件和内存中所有主库元数据) - 执行:
SET GLOBAL read_only = OFF;(新主必须可写) - 可选但推荐:
RESET MASTER;—— 清空本地 binlog 并新建第一个文件(避免后续其他从库拉取到旧主残留的 binlog 名称,引发Could not find first log file name in binary log index file错误)
让其他从库指向新主库
老从库不改源,就会继续连旧主(已只读或宕机),表现为 Slave_IO_Running: No + Last_IO_Error 报连接拒绝或认证失败。
- 在每个待切换的从库上执行:
CHANGE MASTER TO MASTER_HOST='新主IP', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='xxx', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154; -
MASTER_LOG_FILE和MASTER_LOG_POS必须用新主库当前的SHOW MASTER STATUS结果,不能抄旧值 - 执行完
CHANGE MASTER TO后,必须跟START SLAVE;,否则状态仍是NO - MySQL 8.0.23+ 支持
RESTART SLAVE,它会自动先STOP再START,但低版本必须分两步写清楚
真正麻烦的从来不是命令本身,而是位点对齐的时机判断、read_only 的权限边界、以及应用层 DNS 或连接池缓存没清干净——这些地方一漏,切完立刻出问题,但错误日志里往往只显示“连接拒绝”或“复制中断”,根本看不出根源在哪。











