mysql时区必须通过my.cnf中default-time-zone='+08:00'配置并重启生效,time_zone是sql变量不可写入配置文件;timestamp受时区转换影响而datetime不受。

MySQL 的 time_zone 不是改个参数就能同步本地时间的——它必须和系统时间、NTP、配置方式、字段类型四者对齐,否则 NOW() 看起来“慢 8 小时”或 TIMESTAMP 存进去就变样。
my.cnf 里该写 default-time-zone 还是 time_zone
只能写 default-time-zone,这是配置文件中唯一合法的全局时区设置项。time_zone 是 SQL 层变量名,写进 my.cnf 会直接导致 MySQL 启动失败或被忽略。
-
default-time-zone = '+08:00'—— 推荐,简单、稳定、不依赖系统时区表 -
default-time-zone = 'Asia/Shanghai'—— 需提前导入时区表,否则启动报错ERROR 1298 (HY000): Unknown or incorrect time zone - 改完必须重启 MySQL:
systemctl restart mysqld(热重载不生效) - 验证是否生效:
SELECT @@global.time_zone;应返回+08:00,不是SYSTEM
SET time_zone = '+08:00' 只对当前会话有效
这条语句不能替代配置文件修改,它只影响当前连接。老连接不会自动更新,新连接也不会继承——除非你显式设了 default-time-zone。
-
SET time_zone = '+08:00';—— 当前会话立即生效 -
SET GLOBAL time_zone = '+08:00';—— 新建连接默认用这个值,但 MySQL 重启后丢失 - 应用层(如 Python pymysql、Java JDBC)应在建连后主动执行
SET time_zone = '+08:00';,否则可能因客户端时区不同导致NOW()结果不一致 - 注意:
@@session.time_zone和@@global.time_zone可能不同,查的时候要一起看
JDBC 连接报 “Server returns invalid timezone” 怎么修
这是驱动读到 MySQL 返回 SYSTEM 时区后无法解析导致的,根本原因还是服务端没配 default-time-zone,或者客户端 URL 没补全时区参数。
- URL 必须加
&serverTimezone=GMT%2B8或&serverTimezone=Asia/Shanghai(推荐后者,部分老驱动不认GMT%2B8) - 不要只写
useTimezone=true,它只是开启转换逻辑,没指定具体时区照样报错 - 如果用
serverTimezone=Asia/Shanghai,确保 MySQL 已加载时区表(mysql.time_zone_*非空),否则驱动会 fallback 到 SYSTEM 并失败 - Spring Boot 配置示例:
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&useSSL=false
TIMESTAMP 字段为什么存进去就“变时间”
因为 TIMESTAMP 类型强制转 UTC 存储,读取时再按当前 time_zone 转回——而 DATETIME 完全不参与任何转换,原样存、原样读。
- 插入
'2024-01-01 12:00:00'到TIMESTAMP字段,在+08:00下实际存的是2024-01-01 04:00:00(UTC) - 若会话
time_zone是+00:00,查出来就是2024-01-01 04:00:00;若改成+08:00,就变回2024-01-01 12:00:00 - 新表设计优先用
DATETIME,除非你明确需要跨时区归一化时间基准 - 已有
TIMESTAMP字段,务必确保所有客户端连接都设相同time_zone,且服务端default-time-zone固定,不能是SYSTEM
最容易被忽略的点:系统时间不准(比如没开 NTP)、/etc/localtime 软链接损坏、容器里没挂载时区文件、MySQL 启动早于系统时区设置完成——这些都会让 default-time-zone 配得再准也白搭。











