MySQL时区需系统时区、my.cnf的default-time-zone、字段类型(TIMESTAMP/DATETIME)及容器环境四者对齐:先设系统时区为Asia/Shanghai,再配default-time-zone='+08:00',优先用DATETIME,容器中需同步NTP并验证@@global.time_zone。
MySQL 自身不管理时区偏移,完全依赖系统时区(/etc/localtime)或显式配置的 default-time-zone。如果 Linux 系统时区是 UTC 而业务要求使用 Asia/Shanghai,但 MySQL 没配,会导致 NOW()、CURDATE()、日志时间戳全错,且无法通过 SQL 临时修正所有场景(如 InnoDB 表的隐式时间列默认值)。
timedatectl status 确认系统时区是否为 Asia/Shanghai;不是则运行 sudo timedatectl set-timezone Asia/Shanghai
/etc/localtime 是否为指向 /usr/share/zoneinfo/Asia/Shanghai 的软链接:ls -l /etc/localtime
systemd-timesyncd 或 chronyd 服务确保系统时间已同步:sudo systemctl restart chronyd && sudo chronyc tracking
仅靠系统时区不够。MySQL 启动时读取 default-time-zone 值初始化时区缓存,若未配置,会 fallback 到 SYSTEM(即系统时区),但某些版本或容器环境可能行为不稳定。更重要的是:该参数影响 TIMESTAMP 类型字段的存储/读取逻辑——它始终转为 UTC 存储,查询时再按此参数转回本地时间。
[mysqld] 段添加:default-time-zone = '+08:00'(推荐用固定偏移,避免夏令时歧义)
default-time-zone = 'Asia/Shanghai':MySQL 依赖 mysql.time_zone* 表支持命名时区,需手动加载,且容易因表损坏或缺失导致启动失败sudo systemctl restart mysql(Debian/Ubuntu)或 mariadb(CentOS/RHEL)SELECT @@global.time_zone, @@session.time_zone;,应返回 +08:00
TIMESTAMP 自动转换时区,DATETIME 完全不转换——这是最常被忽略的底层差异。例如插入 '2025-01-01 12:00:00' 到 TIMESTAMP 字段,在 +08:00 时区下实际存为 UTC 时间 2025-01-01 04:00:00;而 DATETIME 字段原样存入、原

DATETIME,除非明确需要跨时区自动归一化TIMESTAMP,确保应用层和数据库层时区一致,否则 WHERE ts > '2025-01-01' 可能因会话时区不同产生意外结果SHOW CREATE TABLE your_table\G,确认关键时间字段类型及默认值(如 CURRENT_TIMESTAMP 是否带 ON UPDATE)Docker 或 Kubernetes 中,MySQL 容器若挂载了宿主机的 /etc/localtime,但未同步宿主机的 NTP 配置,或容器启动早于宿主机时间同步完成,会导致 MySQL 读到错误的初始时间。
MYSQL_TIME_ZONE=+08:00(部分镜像支持该变量自动注入 my.cnf)/etc/localtime,应同时挂载 /etc/timezone(Debian 系)或确保容器内 timedatectl 可用until chronyc tracking | grep -q "System clock"; do sleep 1; done,再启动 mysqldmy.cnf 后没重启服务,或者重启了但没验证 @@global.time_zone 的实际值。