mysqlbinlog可实现时间点恢复,但必须先确认log_bin=ON、binlog_format=ROW、server_id非零且目标binlog文件未被purge;再用--start-datetime缩小范围,定位COMMIT上方的end_log_pos作为精确恢复位置,配合--stop-datetime="误操作前1秒"和--database限定库安全重放。

mysqlbinlog 能做到,但必须先确认 binlog 已开启且格式为 ROW,否则时间点恢复大概率失败或数据不一致。
确认 binlog 是否可用且格式正确
没开 binlog 或用 STATEMENT 格式,--start-datetime 就是摆设。
- 执行
SHOW VARIABLES LIKE 'log_bin';,返回ON才算启用 - 执行
SHOW VARIABLES LIKE 'binlog_format';,值必须是ROW(MIXED在部分场景下可能跳过事件,不推荐用于精确恢复) - 执行
SHOW VARIABLES LIKE 'server_id';,即使单机也得设非零值,否则某些 MySQL 版本会拒绝写入 binlog - 执行
SHOW BINARY LOGS;,检查目标时间范围内的文件(如mysql-bin.000012)是否还在;若已触发expire_logs_days清理,就无法回溯
定位目标时间点对应的位置(position)
别信“时间戳直接对应某条 SQL”,mysqlbinlog 的 --start-datetime 匹配的是事件写入 binlog 的时间,不是事务提交时刻;跨文件事务更需谨慎。
- 先用
mysqlbinlog --base64-output=DECODE-ROWS -v --start-datetime="2026-08-05 14:22:00" --stop-datetime="2026-08-05 14:23:00" /var/lib/mysql/mysql-bin.000012缩小范围 - 在输出里找
COMMIT行,它上面紧挨着的end_log_pos值才是你要的 position —— 这个位置代表事务结束时的偏移量,用它恢复才不会丢数据 - 如果事务横跨多个 binlog 文件(比如从
mysql-bin.000012开始、在mysql-bin.000013提交),必须把两个文件都纳入解析范围,只取其中一段会导致事务状态错乱
过滤并安全重放 binlog 到指定时间
直接管道执行 mysqlbinlog | mysql 容易因 DDL、权限语句或 GTID 冲突中断,生产环境务必分步操作。
- 加
--database=myapp限定库名,避免误刷其他库的变更 - 用
--stop-datetime="2026-08-05 14:22:59"(比误操作时间早 1 秒),而不是--start-datetime—— 恢复是“重放到”而非“从某时开始” - 生成 SQL 文件再人工检查:
mysqlbinlog --stop-datetime="2026-08-05 14:22:59" mysql-bin.000012 > restore.sql,删掉里面的DROP DATABASE、TRUNCATE TABLE等危险语句 - GTID 环境下禁用
--start-position,改用--skip-gtids生成无 GTID 的 SQL,否则导入会报GTID already executed
恢复前必须做的两件事
全量备份 + 停写,缺一不可。binlog 不是备份,它只记录变更。
- 先恢复一个早于目标时间点的完整备份(
mysqldump或xtrabackup),确保基础数据一致 - 恢复期间停写(或切到从库操作),否则新写入会污染 binlog 事件链,导致重放后主键冲突、外键失效或自增 ID 错乱
- 测试库验证:把生成的 SQL 导入测试实例,对比表行数、关键字段值和时间戳,别等上线才发现
@1=占位符没解码、或NOW()被重放成错误时间
mysqlbinlog 不会告诉你,得靠人工比对 end_log_pos 和 timestamp 字段。


















