能恢复,但前提是log_bin=ON、binlog_format=ROW、binlog_row_image=FULL且误删前的binlog未过期;缺一不可,否则无法解析被删行镜像,恢复即失败。

能恢复,但前提是 log_bin 是 ON、binlog_format 是 ROW、且误删发生前的 binlog 文件还没被自动清理掉。缺一不可。
确认 binlog 是否可用且格式正确
这是所有操作的前提,不是“可做可不做”,而是“不满足就直接放弃”。很多恢复失败,卡在这一步根本没查清。
-
SHOW VARIABLES LIKE 'log_bin';必须返回ON,否则日志压根没记过任何变更 -
SHOW VARIABLES LIKE 'binlog_format';必须是ROW,MIXED有风险,STATEMENT基本无法还原单条数据 -
SHOW VARIABLES LIKE 'binlog_row_image';建议检查是否为FULL(默认值),否则可能缺失旧值字段,导致反向构造 INSERT 失败 -
SHOW BINARY LOGS;看输出的文件列表和大小,确认最近的 binlog 文件还存在,没被PURGE或expire_logs_days清掉
定位误删事务的起始位置和对应 binlog 文件
别指望靠 grep DELETE 找到 SQL 文本——在 ROW 格式下,DELETE 操作不会以文本形式出现,它藏在 Delete_rows_event 里。你得靠时间或偏移量定位。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 如果知道大概误删时间(比如 2026-09-21 14:22:05),用
mysqlbinlog --start-datetime="2026-09-21 14:21:00" --stop-datetime="2026-09-21 14:23:00" /var/lib/mysql/mysql-bin.000005缩小范围 - 解析时必须加
--base64-output=DECODE-ROWS -v,否则看到的是乱码,看不出哪段是删了哪些行 - 重点找以
BEGIN开头、含Delete_rows: table_id、紧接着是### DELETE FROM `db`.`table`和多行### @1=...字段值的块——这就是你要的“被删前镜像” - 记下这个事务的起始
position(比如12345)和结束position(比如12987),后续跳过要用
生成可执行的恢复 SQL 并安全回放
手写 INSERT 是下策,容易漏字段、错类型、丢 NULL;用工具解析是常态,但要注意输出是否可信。
- 推荐先用开源工具
binlog2sql:它能把Delete_rows_event直接转成带字段名的INSERT语句,命令类似python binlog2sql.py -h127.0.0.1 -P3306 -uuser -ppass --flashback --start-file='mysql-bin.000005' --start-position=12345 --stop-position=12987 - 生成的 SQL 务必先导出到文件,用
head/grep检查前几条是否字段对得上、主键没重复、时间戳合理 - 不要直接在生产库执行!建个临时库或测试实例导入验证,确认数据能插进去、内容无误再走下一步
- 回放完恢复 SQL 后,还要重放误删事务之后的 binlog(跳过那个事务),用
mysqlbinlog --exclude-gtids="xxx-xxx:12345-12987" ... | mysql -u...或分段重放,否则会丢掉误删后新增/修改的数据
TRUNCATE 或 DROP 场景下 binlog 几乎无效
这是最容易误判的一点:很多人以为 “开了 binlog 就万能”,但 TRUNCATE TABLE 不记录行级事件,DROP TABLE 只记 DDL 语句,没有字段值快照。这时候 binlog 能帮的只有重建表结构和补回之后的增删改,原始数据只能靠备份。
-
TRUNCATE在ROW格式下也只产生一个Queryevent,内容就是TRUNCATE TABLE t,没有行数据 -
DROP TABLE同理,mysqlbinlog输出里你能看到DROP TABLE `t`,但看不到这张表之前存过什么 - 如果你只有 binlog、没备份、又碰上这两种操作,基本等于数据永久丢失——这不是技术问题,是运维策略缺陷


















