当前时区是否为SYSTEM或UTC需执行SELECT @@global.time_zone, @@session.time_zone;验证:若返回SYSTEM则跟随系统时区,若为+00:00或UTC则比北京时间慢8小时;再用SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);确认差值应为08:00:00。

确认当前时区是否真为SYSTEM或UTC
很多问题其实不是“没设”,而是设了但没生效,或者误以为已生效。先连上 MySQL 执行:SELECT @@global.time_zone, @@session.time_zone;。如果返回 SYSTEM,说明 MySQL 正在跟随系统时区;若返回 +00:00 或 UTC,则默认就是 UTC——这正是北京时间(+08:00)慢 8 小时的根源。
再补查一句:SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);。理想结果应是 08:00:00;如果返回 00:00:00,说明 NOW() 实际输出的是 UTC 时间,时区根本没切过来。
永久生效必须改 my.cnf / my.ini 的 [mysqld] 段
default-time-zone 是唯一能保证服务重启后仍为 +08:00 的配置项,它作用于全局且优先级高于系统时区。临时 SET 不写入配置文件,重启即丢。
编辑配置文件(Linux 通常为 /etc/my.cnf 或 /etc/mysql/my.cnf;Windows 多为 C:\ProgramData\MySQL\MySQL Server 8.0\my.ini),在 [mysqld] 下新增一行:
default-time-zone = '+08:00'
注意:default-time-zone 不能写成 time-zone 或 timezone;值必须带引号、用 +08:00 格式(不要写 +8:00 或 CST);修改后必须重启服务:systemctl restart mysqld(Linux)或通过服务管理器重启(Windows)。
SET GLOBAL time_zone 只影响新连接,且权限受限
执行 SET GLOBAL time_zone = '+08:00'; 后,现有连接的 @@session.time_zone 不变,只有后续新建连接才会继承这个全局值。它适合紧急测试,但不可替代配置文件。
常见报错:ERROR 1227 (42501): Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN privilege(s) for this operation。这意味着当前用户没有足够权限——普通应用账号几乎都不该有此权限,别硬加,直接走配置文件更安全可靠。
-
SET time_zone = '+08:00';只影响当前会话,退出即失效 -
SET GLOBAL time_zone需要高权限,且不持久 -
asia/shanghai这类命名时区需提前导入时区表(mysql_tzinfo_to_sql),否则报错 1298,没必要折腾
TIMESTAMP 和 DATETIME 的行为差异必须同步理解
即使时区设对了,TIMESTAMP 字段仍会自动按当前会话时区做转换(存 UTC,读本地时区),而 DATETIME 始终原样存储、不转换。如果你的应用依赖 NOW() 或 CURRENT_TIMESTAMP 自动填充,并希望字段值直接对应北京时间,那必须确保:@@session.time_zone 是 +08:00,且建表时明确用 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ——否则可能在跨时区客户端读出来的时间“看起来对”,实则底层已错位。
最容易被忽略的一点:JDBC 连接串里若显式写了 serverTimezone=UTC,会覆盖 MySQL 服务端设置,导致 TIMESTAMP 解析出错。此时必须同步改成 serverTimezone=GMT%2B8 或 serverTimezone=Asia/Shanghai。


















