relay log 损坏可明确通过 last_error 中“relay log read failure”及 slave_sql_running=no、seconds_behind_master=null、relay_log_pos停滞来判断;验证需用 mysqlbinlog 解析 relay_log_file,报错即确认损坏;修复须先 stop slave,再据 gtid 启用与否选择跳过或 reset slave 重置起点;预防需配置 relay_log_recovery=on、sync_relay_log=1 等参数并分离 relay log 存储路径。

Relay log read failure 是 relay log 损坏的明确信号
看到 Last_Error: Relay log read failure: Could not parse relay log event entry,且 Slave_SQL_Running 为 No、Seconds_Behind_Master 为 NULL、Relay_Log_Pos 停滞不动,基本可确认是 relay log 文件损坏,不是主库 binlog 问题、网络中断或权限错误。
验证方法很简单:从 SHOW SLAVE STATUS\G 中提取 Relay_Log_File(比如 mysqld-relay-bin.000121),然后执行:
mysqlbinlog /var/lib/mysql/mysqld-relay-bin.000121 | head -n 20
若报 unknown binlog event type 或直接崩溃,即确认损坏。注意:Relay_Master_Log_File 和 Exec_Master_Log_Pos 是主库位点,和 relay log 是否损坏无关,不能用来判断损坏源。
跳过损坏 relay log 的两种安全路径
必须先 STOP SLAVE,否则任何操作都可能引发错位或启动失败。跳过方式取决于是否启用 GTID:
- 未启用 GTID:查出下一个 relay log 文件名(如当前坏的是
mysqld-relay-bin.000121,下一个是mysqld-relay-bin.000122),位置固定设为4;运行CHANGE MASTER TO RELAY_LOG_FILE='mysqld-relay-bin.000122', RELAY_LOG_POS=4 - 已启用 GTID:
sql_slave_skip_counter完全失效;需手动设置GTID_NEXT,再BEGIN; COMMIT;(其中 GTID 序号来自SHOW SLAVE STATUS\G中的Retrieved_Gtid_Set与Executed_Gtid_Set差集),最后START SLAVE
切记:不能删文件后直接 START SLAVE —— MySQL 不会自动重建 relay log,反而报 Failed to open the relay log。
用 RESET SLAVE + CHANGE MASTER TO 重置 SQL 线程起点
这是最稳妥、不丢事件也不重复执行的做法,适用于你仍信任 IO 线程已拉取的数据:
STOP SLAVE- 记下
SHOW SLAVE STATUS\G中的Master_Log_File(如mysql-bin.000123)和Master_Log_Pos(如456789)——这是 IO 线程最新拉到的位置,唯一可信坐标 -
RESET SLAVE:清空所有 relay log 文件及relay-log.index,同时重置Relay_Master_Log_File和Exec_Master_Log_Pos -
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000123', MASTER_LOG_POS=456789:让 SQL 线程从此处开始执行
该流程绕过了损坏的 relay log,但保证了所有已拉取事件都会被重新解析并执行,无丢失、无跳跃。
预防比修复更重要:关键配置必须开启
relay log 损坏多由异常断电、kill -9 mysqld 或误删文件引发,靠人工恢复既慢又易错。以下配置应写入 my.cnf 并重启生效:
-
relay_log_recovery=ON:MySQL 启动时自动丢弃不完整的 relay log,重建新文件 -
sync_relay_log=1:每次写入 relay log 都强制刷盘,避免缓存丢失 -
relay_log_info_repository=TABLE且sync_relay_log_info=1:防止位点丢失导致跳过错误
特别注意:relay_log_recovery 不支持动态修改,必须重启;expire_logs_days 对 relay log 完全无效,它只控制主库 binlog。
真正容易被忽略的是磁盘路径 —— relay log 默认和 datadir 共用同一分区,一旦 SQL 线程卡住(比如遇到大事务或表损坏),旧 relay log 就无法被自动 purge,磁盘瞬间打满。长期方案必须把 relay_log 和 relay_log_index 迁到独立挂载点,并确保属主、权限、索引路径三者严格匹配。











