MySQL时差8小时主因是default-time-zone未设为'+08:00'或客户端未同步声明时区;需查@@global.time_zone与@@session.time_zone,验证TIMEDIFF(NOW(),UTC_TIMESTAMP)返回+08:00,并统一用DATETIME+应用层时区控制。
MySQL 时间差 8 小时,90% 是因为 default-time-zone 没设对,或客户端连接没同步声明时区——光靠 SET time_zone 临时改,治标不治本。
别只信 NOW(),它受会话时区影响,容易误判。先执行:
SELECT @@global.time_zone, @@session.time_zone;
常见错误组合:
SYSTEM + SYSTEM:MySQL 完全依赖系统时区,而 Docker 容器或精简 Linux 镜像默认是 UTC+00:00 + +00:00:服务端硬设了 UTC,但业务需要东八区+08:00 + SYSTEM:全局设对了,但某个应用连接时显式覆盖了会话时区再补一句验证:
SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);
返回 +08:00 才算真正对齐东八区。
编辑配置文件(如 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段下加:
default-time-zone = '+08:00'
注意三点:
'+08:00',别写 Asia/Shanghai——Alpine 等精简镜像常缺 tzdata,MySQL 启动直接失败sudo systemctl restart mysql,SET GLOBAL time_zone 只是临时方案,重启即丢SELECT @@global.time_zone,确认返回 +08:00 而不是 SYSTEM
即使服务端设成 +08:00,客户端驱动仍可能按自己规则解析时间,导致双重转换错乱:
?serverTimezone=Asia/Shanghai&useTimezone=true,GMT%2B8 在部分驱动里不被识别pymysql:初始化连接时加参数 timezone='+08:00',不能依赖服务端mysql2:配置项写 timezone: '+08:00',否则默认用 UTC 解析 TIMESTAMP
mysql 客户端:每次连进去手动 SET time_zone = '+08:00',仅当前会话有效漏掉任意一环,INSERT INTO t (ts) VALUES (NOW()) 写进去的时间就可能比预期早/晚 8 小时。
这是最隐蔽也最致命的坑:
TIMESTAMP:存入时强制转 UTC,读取时按当前会话时区转回字面值——所以改会话时区,同一条记录查出来显示的时间就变DATETIME:存啥是啥,完全不转换——哪怕你把服务端改成 +08:00,已存的 DATETIME 字段也不会“自动修正”DATETIME 存了 UTC 时间,但业务一直当北京时间用,那现在改任何配置都救不回来,只能跑 UPDATE t SET dt_col = DATE_ADD(dt_col, INTERVAL 8 HOUR) 批量修正线上系统建议统一用 DATETIME,并明确约定所有写入时间都按东八区字面值处理,把时区逻辑收在应用层,避免数据库层隐式转换失控。