能恢复,但前提是Binlog已启用、格式为ROW且日志未过期;必须验证log_bin=ON、binlog_format=ROW、binlog_row_image=FULL,并用position精准定位误删事务,反向生成INSERT后跳过原事务重放。

能恢复,但前提是 Binlog 已启用、格式为 ROW、且日志文件未被清理。缺一不可——尤其是 log_bin=OFF 或 binlog_format=STATEMENT,直接宣告恢复失败。
确认 Binlog 是否可用且配置正确
很多团队在出事才查配置,结果发现根本没开 Binlog,或开了却是 STATEMENT 格式,导致删了也“看不见”数据。必须立刻验证三项:
-
SHOW VARIABLES LIKE 'log_bin';—— 值必须是ON,否则无日志可溯 -
SHOW VARIABLES LIKE 'binlog_format';—— 必须是ROW(MIXED不稳定,STATEMENT无法还原被删行内容) -
SHOW VARIABLES LIKE 'binlog_row_image';—— 推荐FULL(默认值),避免字段缺失导致反向 INSERT 失败
顺手执行 SHOW MASTER STATUS; 记下当前 File 和 Position,这是后续定位的起点。别跳过这步——mysql-bin.000027 可能正在写入,但误删操作可能在 000025 里。
快速定位误删事件的位置或时间范围
别全文解析所有 binlog 文件,效率太低。优先用时间+关键词双过滤:
- 如果知道大概时间(比如运维报警显示“14:22 出现大量 DELETE”),用:
mysqlbinlog --start-datetime="2026-06-13 14:20:00" --stop-datetime="2026-06-13 14:25:00" /var/lib/mysql/mysql-bin.000025 | grep -A 3 -B 3 "DELETE FROM `orders`" - 如果不确定时间,但知道表名和操作类型,先查最近几个 binlog 文件名:
SHOW BINARY LOGS;或ls -lt /var/lib/mysql/mysql-bin.* - 对疑似文件加
-v --base64-output=DECODE-ROWS解析,重点找Delete_rows事件块,里面含被删行的完整字段值(这才是能反向生成 INSERT 的关键)
注意:mysqlbinlog 输出中每个事务以 BEGIN 开头、COMMIT 结尾;#at 123456 是该事件在文件内的字节偏移位置,比时间戳更精确,适合后续切片使用。
提取并安全重放恢复 SQL
直接把整段 binlog 导出成 SQL 再导入,风险极高——可能混入 DROP、UPDATE 或其他无关事务。稳妥做法是分段提取 + 人工校验:
- 用 position 精确切片(推荐):
mysqlbinlog --start-position=123456 --stop-position=789012 /var/lib/mysql/mysql-bin.000025 > recovery.sql - 打开
recovery.sql,手动删除或注释掉所有DROP TABLE、DELETE FROM、TRUNCATE行(TRUNCATE不记 binlog,但万一有 DDL 混入呢) - 只保留
INSERT和你从Delete_rows反向生成的INSERT(可用binlog2sql工具辅助,命令如:python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'pwd' -dtest -tstudent --start-file='mysql-bin.000025' --start-pos=123456 --stop-pos=789012 -B) - 恢复前务必在测试库执行一遍,确认无主键冲突、字段顺序/类型匹配、无重复插入
别在生产库直接跑脚本。哪怕加了 --database=your_db,也不能保证跨库语句被完全过滤。
恢复后必须跳过原误删事务
重放完恢复 SQL 后,数据库状态停在误删前一刻。但 binlog 后续还有新写入——如果不跳过那个误删事务,重放后续 binlog 时会再次执行 DELETE,等于白干。
- 用
mysqlbinlog查出误删事务的起始position(即#at xxxxx后紧跟BEGIN的位置) - 在从当前
SHOW MASTER STATUS位置开始的后续 binlog 中,用--exclude-gtids(GTID 模式)或--stop-position+--start-position跳过该事务 - 最简方式:停应用 → 记下当前
File/Position→ 手动SET GLOBAL sql_log_bin = OFF;执行恢复 SQL → 再SET GLOBAL sql_log_bin = ON;→ 恢复应用连接
真正容易被忽略的是:恢复完成后,binlog_row_image 若曾被临时改过,要核对是否已恢复为 FULL;另外,expire_logs_days 是否足够长,这次事故是否暴露了日志保留策略的短板。


















