MySQL从库relay-log损坏导致START SLAVE失败时,必须放弃旧中继日志链,通过RESET SLAVE ALL后重新定位主库binlog位置或启用GTID自动同步,并严格校验数据一致性。

MySQL 从库崩溃后 relay-log 文件损坏,START SLAVE 报 Could not parse relay log event entry
直接重放中继日志失败,说明 relay-log 已损坏或不连续,不能靠跳过事件硬扛。此时必须放弃当前中继日志链,重建同步起点。
- 先停掉复制:
STOP SLAVE;,避免进一步写入损坏的relay-log - 确认主库当前位点:
SHOW MASTER STATUS;,记下File和Position - 清空从库中继日志:
RESET SLAVE ALL;(注意:这会删除master.info和relay-log.info,但不删已应用的 binlog 数据) - 用
CHANGE MASTER TO指向主库最新binlog位置,而非旧中继日志位置
用 mysqlbinlog 手动拉取主库 binlog 并重放,绕过中继日志
当从库无法自动拉取 binlog(比如网络隔离、主库 binlog 被清理),就得本地下载再回放。关键不是“怎么下载”,而是“从哪开始、到哪结束、怎么保证幂等”。
- 起始位置必须对齐从库已执行的最后一个事务:查
SHOW SLAVE STATUS\G中的Exec_Master_Log_Pos和对应Relay_Master_Log_File - 下载命令示例:
mysqlbinlog --read-from-remote-server --host=主库IP --user=replica --password=xxx mysql-bin.000012 --start-position=12345 > /tmp/fetch.sql - 重放前先检查 SQL 是否含
DROP TABLE或CREATE DATABASE等危险语句——从库通常不该执行 DDL,除非主从结构一致且你明确允许 - 用
mysql -u root -e "source /tmp/fetch.sql"回放,别用管道直连,否则出错无法中断
CHANGE MASTER TO ... MASTER_AUTO_POSITION = 1 能否跳过损坏中继日志?
可以,但前提是主从都开启 GTID,且从库 gtid_executed 集合完整。GTID 模式下,中继日志只是临时缓存,真正恢复依据是 GTID set 对齐,不是文件+位置。
- 确认主库
gtid_mode = ON,且enforce_gtid_consistency = ON - 从库执行
RESET SLAVE ALL;后,用CHANGE MASTER TO MASTER_AUTO_POSITION = 1;即可 - 如果报
Client requested master to start replication from position > file size,说明从库gtid_executed记录异常,需手动补全:SET GLOBAL gtid_purged = 'xxx-yyy:1-100'; - GTID 恢复不依赖中继日志内容,但依赖
gtid_executed的准确性——崩溃后若未刷盘,这个值可能滞后,得结合SELECT @@GLOBAL.gtid_executed;和主库比对
恢复后验证数据一致性,而不是只看 Seconds_Behind_Master = 0
Seconds_Behind_Master = 0 只表示 IO 线程和 SQL 线程没延迟,不代表数据一致。中继日志损坏后重建,最容易漏掉的是非事务性引擎(如 MyISAM)表、或者被 sql_slave_skip_counter 跳过的事务。
- 用
pt-table-checksum在主库运行,结果写入percona.checksums,再在从库上用pt-table-sync --sync-to-master查差异 - 如果无法装 Percona Toolkit,至少对比关键表的
COUNT(*)和MIN(id), MAX(id),尤其关注时间范围最近的分区或分表 - 检查
SHOW SLAVE STATUS\G中的Retrieved_Gtid_Set和Executed_Gtid_Set是否相等;不等说明还有没执行完的事务,即使Slave_SQL_Running: Yes
中继日志损坏本身不难处理,难的是判断“到底丢没丢数据”。很多问题出在以为 START SLAVE 成功了就万事大吉,其实 relay-log 损坏时,SQL 线程可能已经悄悄跳过了一段事务,而错误日志里只有一行模糊的 warning。










