mysql容器默认utc时区导致now()比北京时间慢8小时,需通过docker run时设tz=asia/shanghai和mysql_time_zone='+08:00'、运行时set global time_zone或修改my.cnf的default-time-zone三种方式统一时区,并验证now()、sysdate()、@@global.time_zone及system_time_zone四值一致。

MySQL容器默认用UTC时区,直接启动后 NOW() 比北京时间慢8小时——这不是数据库“错”,而是没告诉它该用哪个时区。必须在容器启动前或启动后明确指定东八区(+08:00 或 Asia/Shanghai),否则所有时间函数、日志、TIMESTAMP字段都会偏差。
创建容器时就设好时区(推荐)
最干净的方式:不进容器、不改配置、不重启,从 docker run 那一刻起就锁定时区。
- 用
-e TZ=Asia/Shanghai设置容器系统时区(影响date、system_time_zone) - 同时加
-e MYSQL_TIME_ZONE='+08:00'(仅对 MySQL 5.7+ 官方镜像生效,会自动写入配置并覆盖time_zone) - 完整命令示例:
docker run -d \ --name mysql-bj \ -e MYSQL_ROOT_PASSWORD=123456 \ -e TZ=Asia/Shanghai \ -e MYSQL_TIME_ZONE='+08:00' \ -p 3306:3306 \ -v /data/mysql:/var/lib/mysql \ mysql:8.0
- 验证:
docker exec mysql-bj mysql -uroot -p123456 -e "SELECT NOW(), @@global.time_zone, @@global.system_time_zone",三者都应显示北京时间
容器已运行,临时改时区(只生效到下次重启)
适合测试或紧急修复,但容器重启后失效。本质是动态修改 MySQL 内部变量,不碰系统或配置文件。
- 进入容器:
docker exec -it mysql-bj mysql -uroot -p123456 - 执行三条语句:
SET GLOBAL time_zone = '+08:00';SET time_zone = '+08:00';FLUSH PRIVILEGES; - 注意:
SET GLOBAL只影响新连接;已有连接仍用旧时区,需重连才能看到效果 - 该方式无法改变
system_time_zone(它由容器系统决定),所以SELECT NOW()虽然对了,但SELECT SYSDATE()在某些场景下可能仍有偏差
修改配置文件实现永久生效(需重启)
适用于需要稳定、可复现、符合运维规范的生产环境。关键点:改的是 MySQL 的 my.cnf,不是容器系统时区。
- 确认配置文件路径:
docker exec mysql-bj ls /etc/mysql/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf(MySQL 5.7+ 多用后者) - 编辑配置:
docker exec -it mysql-bj vi /etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]段落下添加:default-time-zone = '+08:00' - 不要加
system_time_zone—— 这个值由容器系统决定,MySQL 不允许在配置里硬设 - 保存后重启容器:
docker restart mysql-bj,而不是只重启 mysqld 进程(Docker 容器里 service 命令常不可用) - 验证:
docker exec mysql-bj mysql -uroot -p123456 -e "SELECT @@global.time_zone"应返回+08:00
别漏掉容器系统时区(尤其影响日志和备份时间戳)
即使 default-time-zone 设对了,如果容器系统时区仍是 UTC,mysqld 启动日志、mysqlbackup 生成的文件名、SELECT SYSDATE() 等仍可能用错时间。
- 检查当前系统时区:
docker exec mysql-bj date -R,若显示+0000就是 UTC - 安全做法:在
docker run时加-e TZ=Asia/Shanghai(见第一个副标题) - 已运行容器补救:
docker exec -it mysql-bj ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime,然后docker restart mysql-bj - 避免用
cp /usr/share/zoneinfo/PRC /etc/localtime—— PRC 是符号链接,部分精简镜像里可能不存在
真正麻烦的不是改哪一行,而是改完之后不验证。务必用 SELECT NOW(), SYSDATE(), @@global.time_zone, @@global.system_time_zone 四者一起查,缺一不可——因为它们来源不同,可能各自“对”或“错”。











