mysql server在rotate binlog时写、启动或执行reset master时重写binlog.index;server启动及执行show binlog events、purge binlogs时读取并校验该文件。

MySQL 的 binlog.index 文件到底是谁在读、谁在写?
binlog.index 是 MySQL 自动维护的纯文本文件,记录当前所有活跃 binlog 文件的绝对路径(每行一个)。它不被客户端直接操作,而是由 server 在每次 rotate binlog 时自动追加;在启动或执行 RESET MASTER 时被重写。你手动编辑它,MySQL 启动时可能报错退出,或者后续 SHOW BINLOG EVENTS、PURGE BINLOGS 行为异常——因为 server 会校验该文件中列出的每个 binlog 是否真实存在且可读。
常见错误现象:ERROR 1381 (HY000): You are not using binary logging 或 Failed to open log file,往往就是 binlog.index 里残留了已删除但未清理的 binlog 路径。
- 不要用
echo "/path/to/mysql-bin.000123" >> binlog.index手动添加——server 不认这种“脏写” - 执行
PURGE BINLOGS TO 'mysql-bin.000150'后,MySQL 会自动截断binlog.index,只保留从000150开始的条目 - 如果磁盘上 binlog 文件已被
rm删除,但binlog.index还留着对应行,server 启动时会尝试打开失败,直接 abort
为什么 PURGE BINLOGS 有时不生效?
根本原因常是时间点或文件名判断逻辑和你的预期不符。MySQL 的 PURGE BINLOGS BEFORE '2024-06-01 00:00:00' 看的是每个 binlog 文件头里记录的**第一个事件的时间戳**,不是文件修改时间(mtime),更不是创建时间。如果你用 mysqlbinlog --base64-output=decode-rows -v 查看某个 binlog,第一行通常是 # at 4 后跟 #240601 10:23:45 server id ... ——这个时间才决定它是否被 purge。
-
PURGE BINLOGS BEFORE只删binlog.index中排在目标文件之前的全部条目,并同步删除对应物理文件 - 若某 binlog 的第一个 event 时间是 2024-05-31 23:59:59,但它实际写满并 rotate 到磁盘是 2024-06-01 00:01:00,那么
BEFORE '2024-06-01'仍会删掉它 - 务必先用
SHOW BINARY LOGS;确认当前索引状态,再执行 purge,避免误删还在复制链路上的 binlog
如何安全地归档旧 binlog 并保持 binlog.index 可用?
归档不是“移动后改名”,而是“拷贝 + PURGE”。直接 mv mysql-bin.000100 /backup/ 会导致 binlog.index 指向一个不存在的路径,后续任何依赖 binlog 列表的操作都可能失败。
- 正确流程:先
cp mysql-bin.000100 /backup/,再PURGE BINLOGS TO 'mysql-bin.000101'(即保留 000101 及之后) - 如果必须保留部分旧 binlog 供审计但又不想让 server 加载它们,可用
SET GLOBAL expire_logs_days = 0关闭自动清理,再靠外部脚本定期PURGE,别碰binlog.index - 备份脚本里加一句
mysql -e "SHOW BINARY LOGS;" | tail -n +2 | awk '{print $1}' | xargs -I{} cp {} /backup/,比直接cp mysql-bin.*更可靠——它只拷当前 index 认可的文件
当 binlog.index 损坏或丢失时怎么恢复?
它没有冗余副本,也不能从 binlog 文件反向生成完整索引(因为 MySQL 不保证文件名严格连续,比如 mysql-bin.000100 后可能是 mysql-bin.000102,中间缺 101 是合法的)。所以恢复本质是重建可信列表。
- 最稳妥方式:停库 → 手动列出
ls -1 mysql-bin.* | sort -V得到有序文件名 → 用printf "%s\n" $(ls -1 mysql-bin.* | sort -V) > binlog.index重写 → 启动 - 不停库的折中法:用
SHOW BINARY LOGS;输出当前 server 认可的列表,重定向覆盖binlog.index,但注意这会丢弃 server 尚未加载但磁盘仍存在的旧 binlog 条目 - 切记:重写后必须用
mysqlbinlog --no-defaults -v mysql-bin.000xxx | head -20验证至少一个文件能正常解析,否则说明文件损坏或权限不对
真正麻烦的从来不是文件多,而是你以为删了就没了,结果发现 binlog.index 里还挂着一行指向 /tmp/ 下早被清空的路径——MySQL 启动时卡在那里等一个永远打不开的文件。











