MySQL时区错误源于系统、服务、客户端三层时区不一致,需分别检查并统一:修改my.cnf设置default-time-zone;加载时区表支持命名时区;应用连接时显式指定serverTimezone;DATETIME数据不自动转换,TIMESTAMP依赖时区转换,历史偏差需谨慎用DATE_ADD或CONVERT_TZ校正。

MySQL时区错误通常表现为查询结果中的时间比预期快或慢若干小时,比如存储的是 UTC 时间却按本地时区解析,或系统时区、MySQL 服务时区、客户端连接时区不一致。核心问题不是时间本身错了,而是“解释时间的规则”不统一。修复要从这三层入手。
检查并统一 MySQL 服务器默认时区
MySQL 启动时会读取系统时区,但可能被配置文件覆盖。先确认当前生效的全局时区:
SELECT @@global.time_zone, @@session.time_zone;
若返回 SYSTEM,说明使用操作系统时区;若为具体值(如 '+08:00' 或 'Asia/Shanghai'),则以该值为准。不推荐长期用 SYSTEM,因为系统时区变更会影响数据库行为。
- 修改 my.cnf(Linux)或 my.ini(Windows)的 [mysqld] 段,添加:
default-time-zone = '+08:00'
或更规范地使用命名时区(需确保 MySQL 时区表已加载):
default-time-zone = 'Asia/Shanghai'
重启 MySQL 生效。注意:修改后已有 DATETIME 字段不会自动转换,仅影响新写入和查询解释逻辑。
确保时区表已加载(支持命名时区)
若想用 'Asia/Shanghai' 这类名称而非偏移量,必须初始化 MySQL 的时区表(mysql.time_zone* 系列表):
- Linux 下常用命令(需有 root 权限):
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
Windows 不自带 zoneinfo,建议直接使用 '+08:00' 避免依赖。执行后可验证:
SELECT COUNT(*) FROM mysql.time_zone_name WHERE Name LIKE '%Shanghai%';
结果大于 0 表示加载成功。
统一客户端连接时区
即使服务器设为 '+08:00',如果应用连接时指定 serverTimezone=UTC(常见于 JDBC),时间仍会错乱。关键看连接参数:
- JDBC URL 示例(Java):正确写法是 serverTimezone=Asia/Shanghai 或 serverTimezone=GMT%2B8(URL 编码)
- PHP mysqli:连接后执行
mysqli_query($conn, "SET time_zone = '+08:00'"); - 命令行客户端:启动时加
--default-character-set=utf8mb4 --timezone='+08:00',或登录后执行SET time_zone = '+08:00';
建议在应用层显式设置会话时区,不要依赖服务器默认值,尤其在跨时区部署时。
处理已存数据的时间偏差
如果历史数据已按错误时区写入(例如本该存 UTC 却当东八区存了),不能简单改时区配置来“修正”。需分情况处理:
- DATETIME 类型:不带时区,纯字符串存储。原值不变,只改变解释方式。若之前误设 serverTimezone=UTC,而实际存的是北京时间,则查出时间会比真实时间晚 8 小时——此时应把连接时区改为 '+08:00',而非修改数据
-
TIMESTAMP 类型:自动转为 UTC 存储,查询时转回会话时区。若服务器和会话时区混乱,可能导致反复转换。建议统一为 '+08:00' 后,用
CONVERT_TZ()校正关键字段(谨慎操作,先备份)
例如将原按 UTC 存、实为北京时间的 DATETIME 字段批量校正(+8 小时):
UPDATE your_table SET created_at = DATE_ADD(created_at, INTERVAL 8 HOUR) WHERE ...;
务必在低峰期测试并备份。










