在 MySQL 主从复制环境中,利用 binlog 进行数据恢复,核心是借助主库(或已保留完整 binlog 的从库)的二进制日志,重放指定时间段或位置的变更操作,从而将误删、误更新等逻辑错误导致的数据丢失“倒带”回来。关键不在于单纯“回滚”,而是精准定位 + 选择性重放。
确认 binlog 是否启用且可访问
恢复的前提是 binlog 必须开启,并且对应时间段的日志文件未被自动清理。
登录 MySQL 执行 SHOW VARIABLES LIKE 'log_bin';,返回 ON 表示已启用 执行 SHOW MASTER LOGS; 查看当前存在的 binlog 文件列表及大小 检查 expire_logs_days 或 binlog_expire_logs_seconds 设置,确认目标时间点的日志是否还在磁盘上 binlog 文件通常位于 datadir 目录下(如 /var/lib/mysql/mysql-bin.000012),需确保有读取权限定位误操作发生的位置或时间点
越精确的定位,恢复越安全。推荐优先使用时间点(--start-datetime / --stop-datetime),其次用 position(--start-position / --stop-position)。
若知道大致时间(例如“上午10:25误删了 user 表”),可用 mysqlbinlog --start-datetime="2024-06-10 10:20:00" --stop-datetime="2024-06-10 10:30:00" mysql-bin.000012 | grep -A 5 -B 5 "DROP TABLE.*user" 快速筛查 若已知误操作前最后一个安全 position(比如通过 SHOW MASTER STATUS 记录过),可结合 mysqlbinlog --base64-output=DECODE-ROWS -v 解析事件详情,找到 DROP / DELETE 语句前的 end_log_pos 注意:基于时间恢复可能跨多个 binlog 文件,需按顺序处理;基于 position 恢复更精确,但要求 position 连续且无 gap导出并过滤出安全的 SQL(跳过误操作)
直接应用整个 binlog 风险极高,必须剔除问题语句,只保留有效变更。
用 mysqlbinlog 将目标 binlog 转为可读 SQL:mysqlbinlog --skip-gtids --base64-output=DECODE-ROWS -v mysql-bin.000012 > backup.sql 手动编辑或用脚本过滤掉明确的破坏性语句(如 DROP TABLE、DELETE FROM user WHERE 1、TRUNCATE),保留 INSERT/UPDATE/CREATE 等正常操作 更稳妥的方式是使用 --exclude-gtids(配合 GTID)或 --database=db_name 限定库级范围,避免影响其他业务库 建议先在测试库中 source 执行一遍,验证数据效果再上线
在从库或新实例上执行恢复(避免影响主库)
切勿直接在生产主库上重放 binlog——这会引发主从不一致甚至二次故障。
理想做法:拉起一个临时 MySQL 实例(或使用已停用的从库),导入全量备份 + 按需重放 binlog 至误操作前一刻,然后导出修复后的表/库,再回写到生产环境 若必须原地恢复(如无备用实例),应先停止从库复制(STOP SLAVE;),将主库 binlog 导出后,在从库上 SET SQL_LOG_BIN=0; 再 source 恢复SQL,完成后重启复制 特别注意字符集和 sql_mode 一致性,否则可能导致乱码或语法报错,可在恢复前加 SET NAMES utf8mb4; 和 SET sql_mode='STRICT_TRANS_TABLES';