seconds_behind_master 不反映时区问题,default-time-zone 不一致会导致数据错乱而非延迟;必须统一主从 default-time-zone 为 '+08:00'、binlog_format 设为 row,并禁用会话级时间函数,应用层应传入带时区时间或 utc 时间戳。

Seconds_Behind_Master 不会因为 default-time-zone 不一致而“变大”——它根本不会反映时区问题,而是直接失效或给出假值。真正出问题的是数据本身:时间字段写进去就错了,不是延迟,是错乱。
default-time-zone 不一致导致数据错乱,不是复制延迟
- 现象不是
Seconds_Behind_Master升高,而是:- 主库插入
NOW()得到'2026-07-01 22:09:00' - 从库用
SYSTEM或+00:00解析同一 binlog 记录,存成'2026-07-01 14:09:00' -
SHOW SLAVE STATUS\G显示Slave_IO_Running: Yes、Slave_SQL_Running: Yes,但查出来的DATETIME差 8 小时
- 主库插入
- 这种偏差在
binlog_format = STATEMENT下必然发生;即使ROW格式,若字段定义为TIMESTAMP,仍会因会话时区自动转换出错 -
Seconds_Behind_Master依然可能显示0,让你误以为“一切正常”
必须统一主从 default-time-zone 且禁用 SYSTEM
- 在主库和从库的
my.cnf中显式配置相同值:[mysqld] default-time-zone = '+08:00'
- 重启 MySQL 后验证:
SELECT @@global.time_zone;必须返回'+08:00',不能是SYSTEM或空 -
SYSTEM是陷阱:Docker 容器里改系统时区、运维重装系统、甚至timedatectl set-timezone都会让 MySQL 行为突变 -
Asia/Shanghai在 MySQL 5.7+ 要求时区表已加载(mysql_tzinfo_to_sql),不推荐;+08:00是字面偏移,无依赖、最稳
binlog_format 必须设为 ROW,且禁用会话级时间函数
-
STATEMENT模式下,NOW()、CURRENT_TIMESTAMP()会被主库“计算一次”,从库再按自己时区“解释一次”,双重转换必错 - 改为
ROW后,时间值以二进制形式固化在 binlog 中,绕过时区解析 - 应用层不要依赖数据库生成时间:
- 禁止在 INSERT/UPDATE 中直接写
NOW() - 改为应用生成带时区的时间字符串(如
'2026-07-01T22:09:00+08:00')或 UTC 时间戳,再传入DATETIME字段 - 若必须用默认值,定义字段时写
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,并确认explicit_defaults_for_timestamp = ON
- 禁止在 INSERT/UPDATE 中直接写
JDBC 连接串漏配 serverTimezone 会让问题蔓延到应用层
- Java 应用连 MySQL,光靠服务端设
default-time-zone不够 - JDBC 8.0+ 默认把
java.util.Date按 JVM 本地时区转成 UTC 发给 MySQL,MySQL 又按自己的time_zone解析,结果可能偏移 8 小时 - 连接串必须包含:
jdbc:mysql://host:3306/db?serverTimezone=Asia/Shanghai&useTimezone=true -
GMT%2B8多数驱动不识别;Asia/Shanghai是 IANA 标准名,兼容性最好 - Spring Boot 的
spring.datasource.url里也要带上该参数;spring.jackson.time-zone对数据库层完全无效
时区问题最危险的地方在于:它不报错、不告警、Seconds_Behind_Master 正常、复制线程全绿,但数据已经悄悄错位——等业务对账或用户投诉才发现,修复成本远高于初始化就对齐。











