最稳妥方案是修改my.cnf的[mysqld]段添加default-time-zone='Asia/Shanghai'并导入时区表;仅SET GLOBAL time_zone临时生效且需先用mysql_tzinfo_to_sql导入时区数据,否则报错1298。

直接改配置文件最稳妥,default-time-zone = 'Asia/Shanghai' 加上时区表导入,才能真正生效。只用 SET GLOBAL time_zone 是临时的,重启就丢。
为什么 SET GLOBAL time_zone='Asia/Shanghai' 会报错 1298
错误代码 1298 表示 MySQL 没有时区名称支持能力——本质是 mysql.time_zone* 这些系统表为空或未初始化。
- 必须先运行
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql(路径按实际系统调整) - 确认导入成功:执行
SELECT COUNT(*) FROM mysql.time_zone_name WHERE Name = 'Asia/Shanghai';,结果应大于 0 - 如果用的是 Alpine 镜像或极简发行版,
/usr/share/zoneinfo可能不存在,得先apk add tzdata或挂载宿主机时区文件
my.cnf 里 default-time-zone 设置要点
这个配置决定所有新连接的默认会话时区,但前提是它被正确加载且不被覆盖。
- 必须写在
[mysqld]段下,不是[client]或全局段 - 值可以是
'Asia/Shanghai'(推荐),也可以是'+08:00';前者依赖时区表,后者无需导入但不处理夏令时 - 若配置文件有多个
[mysqld]段(比如被 include 拆分),确保该参数落在最终生效的那个段里 - 修改后必须重启 MySQL:
systemctl restart mysqld或容器需重建,service mysql reload不生效
Docker 环境下 TZ 和 default-time-zone 要配合用
只设 TZ=Asia/Shanghai 环境变量,MySQL 本身仍可能读到 SYSTEM 时区——因为 MySQL 启动时读取的是 OS 时区,但后续不自动同步。
- 容器启动时加
-e TZ=Asia/Shanghai,保证系统层时区正确 - 同时挂载自定义
my.cnf,里面明确写default-time-zone = 'Asia/Shanghai' - 验证命令必须跑两遍:
SELECT @@global.time_zone, @@session.time_zone;和SELECT NOW();对照宿主机date输出 - 若用
mysql:8.4或更新镜像,注意部分版本默认禁用时区表加载,需额外加--skip-secure-auth或检查日志中是否有Failed to load timezone information
最容易被忽略的是:即使配置全对,SELECT NOW() 和应用层拿到的时间仍可能差 8 小时——那大概率是 JDBC URL 漏了 serverTimezone=Asia/Shanghai,或者 ORM 默认按 UTC 解析 TIMESTAMP 字段。时区问题从来不是单点配置能闭环的事。


















