MySQL 默认常关闭binlog,需执行SHOW VARIABLES LIKE 'log_bin'确认为ON;否则需在配置文件中添加log-bin和唯一server-id并重启。

binlog 开启没?先确认 MySQL 是否在记录变更日志
增量备份依赖 binlog,但默认很多 MySQL 实例是关闭它的。不检查就动手,后面所有操作都白搭。
执行 SHOW VARIABLES LIKE 'log_bin';,返回 ON 才算启用;如果值是 OFF,得改配置文件(通常是 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),加上:
[mysqld] log-bin = mysql-bin server-id = 1
改完必须重启 MySQL,且 server-id 不能为 0 或重复,否则主从或 binlog 读取会出问题。
- 只开
log-bin不设server-id:MySQL 启动可能失败,或 binlog 写入异常 - 用
mysql-bin.index查看当前 binlog 文件列表,别直接 ls 目录——文件名可能被轮转覆盖 - binlog 格式建议用
ROW(binlog_format = ROW),语句级(STATEMENT)在函数、时间戳、自增等场景下无法精确还原
怎么安全地导出某段时间的 binlog 变更?
不是所有 binlog 都能直接拿来恢复,得挑出“干净区间”:起点要落在完整事务内,终点不能截断事务,否则恢复时报 ERROR 1594 (HY000)。
用 mysqlbinlog 提取时,优先用位置(position)而非时间(--start-datetime 容易跨事务):
mysqlbinlog --base64-output=DECODE-ROWS -v \ --start-position=12345 \ --stop-position=67890 \ /var/lib/mysql/mysql-bin.000001 > changes.sql
-
--base64-output=DECODE-ROWS和-v必须一起用,否则 ROW 格式事件显示为乱码,看不出改了哪行 - 起始 position 推荐用
SHOW BINLOG EVENTS IN 'mysql-bin.000001' LIMIT 10;手动找第一个Write_rows_v1或Query事件的位置 - 避免用
--start-datetime恢复到某个时间点:binlog 时间戳是事件写入时间,不是执行完成时间,高并发下误差可达秒级
恢复时跳过误删库/表,但又不想丢其他数据?
全量恢复 + 增量重放时,如果中间混着 DROP DATABASE 或 TRUNCATE TABLE,直接跑 mysql 导入会把整个库干掉。
两种务实办法:
- 用
mysqlbinlog --exclude-gtids=...(仅 MySQL 5.7+)跳过已知 GTID,但前提是开启gtid_mode=ON - 更通用的做法:用
sed或awk过滤 SQL 文件,比如删掉含DROP DATABASE的整行及后续几行(binlog 中 DDL 后常跟COMMIT):sed '/DROP DATABASE/,/COMMIT/d' changes.sql > safe.sql - 过滤后务必用
grep -E '^(INSERT|UPDATE|DELETE|REPLACE)' safe.sql | head -5确认还剩有效 DML
恢复后发现数据对不上,大概率卡在哪?
常见不是 SQL 执行错,而是 binlog 解析或应用顺序出了偏差。
- ROW 格式下,
mysqlbinlog输出的@1,@2是字段序号,不是列名;如果表结构在备份期间改过(比如加字段),重放时字段错位,数据就塞进错误列 - 跨库操作(如
UPDATE db1.t1 JOIN db2.t2)在 binlog 中只记表名,不记库名,恢复时若当前库不是原库,语句会报错或写错地方 - 恢复前没关
sql_log_bin:重放过程自身又生成新 binlog,导致二次污染,建议加SET sql_log_bin = 0;到 SQL 文件头
最稳妥的验证方式:恢复后立刻查几张关键表的 COUNT(*) 和 MIN(id), MAX(id),和备份前快照比对,别只信“没报错”。











