Seconds_Behind_Master漂移且无报错大概率是主从时区不一致所致:STATEMENT模式下NOW()生成的时间字面量在不同时区解释导致时间偏差,需统一default-time-zone并优先使用UTC_TIMESTAMP()。

SHOW SLAVE STATUS 里 Seconds_Behind_Master 漂移但无报错,怀疑时区问题
这种现象很典型:SQL线程一直显示 Slave_SQL_Running: Yes,Seconds_Behind_Master 却忽大忽小、甚至负值,Last_SQL_Error 为空。不是复制中断,但业务查到的时间字段(比如 created_at)在主从库上差几个小时——大概率是时区没对齐。
MySQL 的 NOW()、CURRENT_TIMESTAMP 等函数依赖于系统时区和会话时区。如果主库用 SYSTEM(即系统默认时区),而从库设成了 +08:00 或 Asia/Shanghai,又或者反过来,STATEMENT 格式下写入的 SQL 就会带“错误时间字面量”,导致从库执行结果偏差。
- 先确认主从当前会话时区:
SELECT @@time_zone, @@system_time_zone; - 检查 my.cnf 是否显式设置了
default-time-zone;没设则默认走SYSTEM,但不同机器的SYSTEM可能不同 - 特别注意 Docker 容器或云主机:宿主机时区 ≠ MySQL 进程时区,
date命令输出不等于@@system_time_zone
STATEMENT 复制模式下 INSERT INTO ... VALUES (NOW()) 导致时间错位
这是时区不一致最直接的“爆点”。主库执行 INSERT INTO log (ts) VALUES (NOW());,binlog 记的是类似 INSERT INTO log (ts) VALUES ('2026-09-28 14:30:00') 这样的字符串。这个字符串按主库时区解释后写入,但从库若时区不同,'2026-09-28 14:30:00' 就会被当成“本地时间”存进去,最终值相差整点。
- RBR 模式不受影响:它记录的是行变更前后的二进制值,不依赖时间函数求值
- 如果必须用 STATEMENT,请强制统一主从的
default-time-zone,且避免在 SQL 中直接调用NOW()、CURRENT_TIMESTAMP,改用UTC_TIMESTAMP()+ 应用层转换 - 临时验证:在从库执行
SET time_zone = '+00:00';后再查刚同步的记录,看时间是否对齐
如何安全验证并修复时区配置差异
别直接改配置重启。先做一致性快照比对,确认问题范围:
- 在主库执行:
SELECT UNIX_TIMESTAMP(NOW()), NOW(), @@time_zone;,记下三值 - 立刻在从库执行同样语句,对比
UNIX_TIMESTAMP(NOW())是否一致(这个值应完全相同);若不一致,说明时区已导致逻辑时间偏移 - 检查
my.cnf:主从都必须有明确的default-time-zone = '+08:00'(推荐用固定偏移,不用Asia/Shanghai,避免夏令时歧义) - 改完配置后,需重启 MySQL 才生效;重启前确保
slave_sql_running = No,否则可能因时区切换导致正在回放的事务出错
为什么 pt-table-checksum 对时区问题“视而不见”
pt-table-checksum 默认对时间类型字段做 MD5(CONVERT_TZ(ts, @@time_zone, '+00:00')) 类似处理,试图抹平时区差异。但它只作用于校验阶段,不影响实际复制行为。更关键的是:如果表里混用了 DATETIME 和 TIMESTAMP,TIMESTAMP 会自动按会话时区转存,而 DATETIME 不转——这时 checksum 可能算出“一致”,但业务读出来就是错的。
- 真正要查时区引发的不一致,得挑几条含时间字段的记录,手工比对
UNIX_TIMESTAMP(ts)值 - 遇到
TIMESTAMP字段,务必确认主从explicit_defaults_for_timestamp设置一致,否则 NULL 行为都不同 - 线上环境建议统一用
UTC_TIMESTAMP()写入 +DATETIME存储,把时区转换全交给应用层
@@time_zone 当作和 sql_mode、character_set 一样纳入初始化检查清单。


















