最准最快的方式是直接查看mysqlbinlog输出中的# at和end_log_pos;起始position恒为4,结束position需用mysqlbinlog -v反查末尾end_log_pos值,rotate事件的end_log_pos即为文件实际结尾位置。

直接看 mysqlbinlog 输出里的 # at 和 end_log_pos,这是最准、最快的方式。别依赖 SHOW BINLOG EVENTS 查起始/结束 position——它查得慢、不准,还容易漏掉 Rotate 事件后的边界。
用 mysqlbinlog 解析单个 binlog 文件并提取位点范围
每个 binlog 文件的起始 position 固定是 4(Format_desc 事件开头),但结束 position 必须从文件末尾反推。最稳的方法是用 mysqlbinlog 加 --base64-output=DECODE-ROWS -v 看完整结构:
-
mysqlbinlog --no-defaults --base64-output=DECODE-ROWS -v /var/lib/mysql/mysql-bin.000020 | tail -n 50—— 查最后几十行,找最后一个end_log_pos值 - 注意结尾常有
Rotate事件:end_log_pos 997表示该文件实际结束于997,下个文件从998开始(不是997 + 1,因为end_log_pos是包含当前事件的结束位置) - 如果文件正在被写入(即
SHOW MASTER STATUS显示的当前文件),end_log_pos可能不等于磁盘文件大小,此时以SHOW MASTER STATUS的Position字段为准
按时间范围快速圈定 position 区间
当只知道异常发生的大致时间(比如“14:22 左右数据被删”),靠肉眼扫日志效率低。先用时间粗筛,再定位精确 position:
- 执行:
mysqlbinlog --no-defaults --start-datetime="2026-06-02 14:20:00" --stop-datetime="2026-06-02 14:25:00" /var/lib/mysql/mysql-bin.000020 | grep -E "(# at |end_log_pos|DELETE|UPDATE|Xid)" | head -n 20 - 找到第一个
# at N就是起始 position,最后一个end_log_pos M就是结束 position(注意:这个M是事务提交点,可作为安全回滚终点) - 若结果为空,说明时间范围跨了多个 binlog 文件,需配合
SHOW BINLOG EVENTS IN 'mysql-bin.000020' LIMIT 1和SHOW BINLOG EVENTS IN 'mysql-bin.000021' LIMIT 1查各文件时间戳
跳过 GTID 和 row 格式带来的解析干扰
启用了 GTID 或 binlog_format = ROW 时,mysqlbinlog 默认输出会夹杂大量 base64 和注释,干扰 position 定位:
- 加
--base64-output=DECODE-ROWS强制解码 row event,否则你看到的# at是逻辑位置,不是物理偏移 - 加
--skip-gtids可跳过 GTID event 的插入(仅用于分析,不用于恢复),避免SET @@SESSION.GTID_NEXT挤占位置信息 - 若只关心 SQL 文本,加
-v --base64-output=DECODE-ROWS;若要提取纯 position 范围,加--verbose --short-form可减少冗余输出
真正容易被忽略的是:position 不是全局连续的,每个 binlog 文件都从 4 开始计数;而 SHOW BINLOG EVENTS 返回的 Pos 是文件内偏移,不能跨文件累加。做增量恢复前,务必确认你拿到的是目标文件内的真实 # at 和 end_log_pos,而不是靠猜或拼接。











