mysql binlog是一套运行时生成的二进制日志机制,只记录数据变更(如insert、update、delete、ddl),不记录select/show;核心用途是主从复制和时间点恢复(pitr)。

MySQL binlog 不是某个具体文件,而是一套运行时生成的二进制日志机制——它只记录数据变更(INSERT、UPDATE、DELETE、CREATE、DROP 等),不记录 SELECT 或 SHOW。它的核心用途就两个:主从复制和时间点恢复(PITR)。能不能用、好不好用,取决于你是否正确开启并配置它。
怎么确认 binlog 当前有没有开
直接执行:SHOW VARIABLES LIKE 'log_bin';
如果返回值是 ON,说明已启用;如果是 OFF,就得动手配了。别信“装完 MySQL 就有”,5.7 默认关,8.0 才默认开——但很多生产环境是 5.7 或手动降级过的 8.0,所以必须查。
顺带看一眼路径和格式:SHOW VARIABLES LIKE 'log_bin_basename';SHOW VARIABLES LIKE 'binlog_format';
前者告诉你日志文件实际写在哪,后者决定日志内容粒度(ROW 是目前最稳妥的选择)。
永久开启 binlog 必须改 my.cnf(不是 SET GLOBAL)
临时用 SET GLOBAL log_bin = ON; 看似能开,但 MySQL 重启后立刻失效,且在多数版本中该语句根本报错(因为 log_bin 是只读变量)。真正生效的方式只有改配置文件:
- 编辑
/etc/my.cnf(Linux)或my.ini(Windows),在[mysqld]段下添加: -
log_bin = /var/lib/mysql/mysql-bin—— 路径必须存在且 MySQL 进程有写权限,否则 mysqld 启动失败 -
server_id = 123—— 必填,主从环境下必须全局唯一;单机也得设,否则某些工具(如mysqlbinlog)解析会出问题 -
binlog_format = ROW—— 强烈建议,避免STATEMENT格式下因函数不确定性导致主从不一致 -
expire_logs_days = 7或binlog_expire_logs_seconds = 604800—— 二者选一,控制自动清理周期,避免磁盘被撑爆
改完必须重启 MySQL:systemctl restart mysqld(或 service mysql restart),然后再次 SHOW VARIABLES LIKE 'log_bin'; 验证。
开了之后怎么快速验证日志真在写
别只看变量,要看到真实文件:
- 执行
SHOW BINARY LOGS;—— 返回至少一个文件(如mysql-bin.000001),说明日志已滚动生成 - 执行
FLUSH LOGS;—— 手动触发日志切换,再跑一次SHOW BINARY LOGS;,应该能看到新文件序号+1 - 检查磁盘目录:
ls -lh /var/lib/mysql/mysql-bin.*(路径以log_bin_basename输出为准),确认文件大小 > 0
如果 SHOW BINARY LOGS; 报错 ERROR 1381 (HY000): You are not using binary logging,说明配置没生效或 MySQL 没读到配置——常见原因是配置写在了错误段(比如写在 [client] 下)、文件编码含 BOM、或 mysqld 启动时用了 --defaults-file 指定了别的配置文件。
ROW 格式下容易忽略的性能坑
binlog_format = ROW 安全,但代价明确:
- 大事务(比如批量更新百万行)会让单个
binlog文件暴涨,甚至远超max_binlog_size设置值(因为事务不能跨文件切分) -
binlog_row_image = FULL(默认)会记录整行变更前后的所有字段,哪怕只改了一个INT字段,也会把整条记录的BLOB也记下来——磁盘和网络压力都翻倍 - 如果业务允许,可设为
binlog_row_image = MINIMAL,只记主键 + 变更字段,但要求表必须有主键或非空唯一键,否则复制会失败
这些参数改了也要重启,且 MINIMAL 在部分旧客户端或中间件里可能不兼容,上线前务必在测试库压测验证。











