必须设为ROW,因STATEMENT模式记录SQL文本,依赖从库重放时的上下文(如NOW()、UUID()等非确定性函数结果不同),而ROW模式记录行级变更前后像,完全规避上下文差异,100%保障主从一致。

必须设为 ROW,不能只依赖默认值或 MIXED —— 尤其在有函数、触发器、时间相关操作的业务中,STATEMENT 模式极易导致主从数据不一致。
为什么 binlog-format=ROW 能避免主从不一致
MySQL 的 STATEMENT 模式只记录原始 SQL,比如 UPDATE t SET ts = NOW(),从库执行时用的是自己的系统时间;而 ROW 模式记录的是“哪一行被改成了什么值”,完全绕过函数求值和会话上下文差异。只要主库写入成功,从库重放的就是确定性的行变更事件。
-
NOW()、UUID()、USER()、LAST_INSERT_ID()等非确定性函数在STATEMENT下必然出错 - 触发器、存储过程内部的语句,在
STATEMENT下可能不会被完整记录或重放 -
ROW日志体积更大,但这是数据一致性的必要代价;磁盘空间比丢数据好救
如何正确设置 binlog-format=ROW
该参数必须写在 [mysqld] 段下,且需配合 log-bin 启用才生效。仅修改变量(如 SET GLOBAL binlog_format = 'ROW')是临时的,重启即失效,主从复制不认这个运行时设置。
- 编辑配置文件(如
/etc/my.cnf或/etc/mysql/my.cnf),在[mysqld]下添加:binlog-format = ROW
- 确保同一配置段中已存在
log-bin(否则binlog-format不起作用) - 确认没有其他配置覆盖它:检查是否有
!includedir引入的其他 conf 文件也设置了binlog-format,优先级以最后加载的为准 - 重启 MySQL:
sudo systemctl restart mysql(或mysqld,依实际服务名)
验证是否真正生效
别只看配置文件写了什么,要查运行时状态。连上 MySQL 后执行:
SHOW VARIABLES LIKE 'binlog_format';
返回值必须是 ROW,且 log_bin 值为 ON。如果仍是 STATEMENT,常见原因包括:
- 配置写在了错误段(比如
[client]或单独的[mysqld_safe]) - MySQL 启动时读取了多个配置文件,后加载的文件里有冲突设置
- 使用了 MySQL 5.7.7 之前版本,
binlog-format不支持动态修改,且某些旧版本默认不启用 binlog - 启用了 GTID 但未同步设置
enforce_gtid_consistency = ON,部分操作会被拒绝,间接影响格式行为
从库也必须用 ROW 吗?
从库自身不需要开启 log-bin,所以它的 binlog-format 设置无效;但从库的 SQL 线程重放 relay log 时,行为由主库写入的 binlog 格式决定 —— 所以只要主库设对了 ROW,从库无需额外配置。但注意:如果从库也想作为新主库(比如做故障切换),它就必须自己也配好 log-bin 和 binlog-format = ROW,否则升主后立刻开始产生不安全日志。
最容易被忽略的一点:即使你确认主库 binlog-format 是 ROW,也要检查 SHOW MASTER STATUS 输出的 File 是否真的在滚动 —— 如果长期没变化,说明 binlog 没真正启用,所有格式设置都白搭。











