mysqlbinlog默认不显示Query事件,必须同时使用--base64-output=DECODE-ROWS和--verbose(或-v)才能还原原始SQL;MySQL 8.0默认binlog_format为ROW,DML操作以行事件记录,需依赖紧邻的Query事件定位误删语句。

mysqlbinlog 默认不显示 Query 事件,必须加 --base64-output=DECODE-ROWS 和 --verbose
MySQL 8.0 默认 binlog_format 是 ROW,这种格式下 DML(如 DELETE/UPDATE)不会直接记录原始 SQL,而是记录行变更的二进制结构。所以直接跑 mysqlbinlog binlog.000001 看不到 DELETE FROM orders WHERE id = 123 这种语句,只能看到一堆 ### DELETE FROM ... 的伪 SQL 块。
要还原出「误删前执行的原始 SQL」,关键不是看 ROW 事件本身,而是找它前面紧邻的 Query 事件——也就是客户端真正发过来的那条语句。但这个事件默认被压缩或隐藏,必须显式启用解析:
-
--base64-output=DECODE-ROWS:把 base64 编码的 ROW 事件解码成可读的###格式 -
--verbose(或-v):强制输出事件头信息,包括Query类型事件和它的 SQL 文本 - 缺一不可,漏掉
--verbose就看不到QUERY_EVENT对应的原始语句
示例命令:
mysqlbinlog --no-defaults --base64-output=DECODE-ROWS -v /var/lib/mysql/binlog.000012 | grep -A 2 -B 2 "DROP TABLE\|DELETE FROM\|TRUNCATE"
如何定位到误删操作所在的 binlog 文件和位置点
不能靠猜文件名,得用 MySQL 自带命令查实时状态。误删后第一件事是登录 MySQL 执行:
-
SHOW BINARY LOGS;:列出当前所有可用 binlog 文件(注意:已过期的会被 purge 掉) -
SHOW BINLOG EVENTS IN 'binlog.000012' LIMIT 20;:查看某文件开头几条事件,确认是否包含目标库表操作 -
SHOW BINLOG EVENTS IN 'binlog.000012' WHERE Info LIKE '%orders%' AND Event_type = 'Query';:精准筛选含表名的 Query 事件
如果 Info 字段里出现 DROP TABLE `production`.`orders`,说明找到了。记下该事件的 Pos(起始位置)和 End_log_pos(结束位置),后续恢复要用。
为什么用 mysqlbinlog --start-position 恢复时容易漏数据
因为一个事务可能跨多个事件,而 Query 事件只是“开始”,后面跟着 Table_map、Delete_rows 等。如果只从 Query 的 Pos 开始截取,会丢掉事务头(比如 GTID_LOG_EVENT 或 BEGIN),导致恢复时报错 ERROR 1785 (HY000)(事务不完整)。
稳妥做法是:找到误删 Query 事件的 Pos 后,往前翻几行,定位到它所属事务的 BEGIN 或 GTID 事件的 Pos 作为 --start-position;结束位置则取 Delete_rows 事件的 End_log_pos,不要停在 Query 行。
- 用
mysqlbinlog -v输出后搜索# at [number]+BEGIN或GTID - 避免用
--stop-datetime精确到秒——binlog 写入有毫秒级延迟,可能切在事务中间
遇到 ERROR 1146 (42S02): Table 'xxx' doesn't exist 还能恢复吗
能,但前提是:表结构定义(CREATE TABLE)还在 binlog 里,且没被 purge。ROW 格式 binlog 不存表结构,但 CREATE TABLE 是 Query 事件,只要它没被轮转掉,就能抽出来。
操作步骤:
- 用
mysqlbinlog -v binlog.000011 | grep -A 50 "CREATE TABLE.*orders"找建表语句 - 若找不到,再查更早的 binlog 文件(
SHOW BINARY LOGS看文件序号) - 把抽出来的
CREATE TABLE语句手动执行,重建空表,再导入 ROW 数据
注意:如果建表语句也丢了,或者用了 IF NOT EXISTS 导致 binlog 里没记录,那就只能靠备份或第三方工具(如 my2sql)反推结构了——这时候 Query 事件就真没了。


















