必须锚定备份时刻的binlog坐标,逻辑备份用–master-data=2写入change master注释,物理备份记录在xtrabackup_binlog_info中;缺失时需查show master status或反向解析binlog。
怎么确定备份时刻对应的 binlog 位置
全量备份不是“拍个快照”就完事,它必须锚定到 binlog 的某个具体坐标,否则后续重放无从谈起。逻辑备份(mysqldump)若加了 --master-data=2,会在 SQL 文件开头写入类似 -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000123', MASTER_LOG_POS=10339767; 的注释;物理备份(如 xtrabackup)则在 xtrabackup_binlog_info 文件里直接记录该信息。
常见错误是直接跳过这步,靠“大概时间”硬猜起始位置——结果重放时跳过关键事务,或重复执行已存在的数据,导致主键冲突、数据错乱。
- 务必用
head -n 20 your_backup.sql | grep "CHANGE MASTER"或cat /path/to/backup/xtrabackup_binlog_info精确提取 - 若备份没带 binlog 位置(比如手动
mysqldump未加--master-data),只能退而求其次:查备份执行时刻的SHOW MASTER STATUS输出,或用mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.* | grep "2026-01-28 02:00:00"反向定位
如何精准截断到误操作前的最后一秒
目标不是“恢复到某时间”,而是“停在误操作发生前的最后一个安全 commit”。用 --stop-datetime 看似方便,但存在风险:binlog 中同一秒可能有多个事件,且日志刷盘延迟会导致实际写入时间晚于语句执行时间。
更可靠的做法是先用 mysqlbinlog 查看目标时间段的原始事件,人工确认误删/误更新语句前的最后一个 COMMIT 或 Xid 事件位置,再用 --stop-position 精确截断。
- 示例:找到误操作前最后一条
COMMIT在mysql-bin.000124的位置1234567,则命令为mysqlbinlog --start-position=10339767 --stop-position=1234567 mysql-bin.000123 mysql-bin.000124 | mysql -u root -p - 跨文件重放时,
mysqlbinlog会自动按顺序拼接,但不能跳过中间文件(比如只选.000123和.000125) - 若启用了 GTID,需加
--skip-gtids并指定--include-gtids='...',否则可能因 GTID 冲突报错ERROR 1840 (HY000)
为什么恢复后数据还是不对
最常被忽略的一点:恢复过程本身会产生新 binlog。如果 MySQL 启动后未禁用 binlog 写入,重放阶段产生的所有 SQL 都会被再次记录进新的 binlog 文件,不仅污染日志,还可能导致后续恢复循环依赖。