根本原因是mysql容器默认使用utc时区,而本地为cst(utc+8),但tz环境变量未设置、my.cnf配置路径错误或未加载、default-time-zone字段名写错、/etc/localtime未同步等任一环节失效,均导致时区设置不生效。

根本原因就一个:MySQL容器默认用 UTC,而你本地是 CST(UTC+8),但关键配置没对上——不是改了就生效,而是改错地方、或只改了一半。
docker run 时没传 TZ 环境变量
官方 MySQL 镜像(如 mysql:8.0)会读取 TZ 环境变量来设置系统时区,进而影响 system_time_zone。不传这个变量,容器内 date 就显示 UTC,@@time_zone 即使设成 '+08:00' 也常被忽略。
- 正确做法:
docker run -e TZ=Asia/Shanghai ... - 注意 Alpine 镜像需先装
tzdata,否则TZ不生效 -
TZ=Asia/Shanghai比TZ=GMT-8更可靠,避免部分版本解析失败
my.cnf 里写了 default-time-zone 但没加载
很多人改了 /etc/my.cnf 或 /etc/mysql/my.cnf,加了 default-time-zone = '+08:00',重启后仍无效——因为 MySQL 根本没读那个文件。
- 先查真实加载路径:
mysqld --verbose --help | grep "Default options" - 常见有效路径是
/etc/mysql/conf.d/(尤其 Docker 官方镜像),不是根目录下的my.cnf - 必须写在
[mysqld]段下,且字段名只能是default-time-zone,不能写成timezone或time_zone - 挂载配置时,确保目标路径存在且权限可读,比如用
-v ./timezone.cnf:/etc/mysql/conf.d/timezone.cnf
SET GLOBAL time_zone 只对新连接生效
执行 SET GLOBAL time_zone = '+08:00' 确实能让后续连接返回正确时间,但已有连接、应用重连、定时事件仍沿用旧值,而且容器重启后清空。
- 临时验证可以,但不能替代配置文件或环境变量
- MySQL 8.0+ 可用
SET PERSIST time_zone = '+08:00'写入持久化变量表,但依赖performance_schema启用,且不如my.cnf明确可控 -
system_time_zone始终由容器系统时区决定,它不变,default-time-zone就可能被降级为 fallback
Docker 容器没同步宿主机时区文件
即使 my.cnf 和 TZ 都设了,如果容器内 /etc/localtime 还指向 UTC,MySQL 启动时仍会把 system_time_zone 识别为 CST(实际是空或乱码),导致 default-time-zone 失效。
- 最稳方案:启动时挂载宿主机时区文件:
-v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro - 进容器手动改也行:
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime,但容器重建就丢 - 验证是否生效:
docker exec mysql-container date输出必须带CST或+0800,不能是UTC
真正卡住人的地方,往往不是“没设”,而是“设了但没生效”——system_time_zone 和 default-time-zone 两层时区逻辑叠加,任何一层断掉都会让时间差回 8 小时。每次修改后,务必用 SELECT @@global.time_zone, @@session.time_zone, NOW(), SYSDATE(), UTC_TIMESTAMP(); 对照着看,三者时间一致才算到位。











