根本原因是Navicat客户端时区与MySQL服务端未对齐,导致TIMESTAMP值在UTC与本地时区转换中偏移或变NULL;需在连接高级设置中显式配置serverTimezone=Asia/Shanghai并启用useTimezone=true,且同步前检查表定义、SQL mode及explicit_defaults_for_timestamp一致性。
Navicat 同步时 TIMESTAMP 字段变 NULL 或偏移 8 小时
根本原因不是数据库时间错了,而是 navicat 客户端会用自己的时区解释 timestamp 值,而 mysql 默认把 timestamp 存为 utc、查出来再转成会话时区——如果 navicat 没设对时区,就会少 8 小时或变成 null。
典型现象包括:
- 同步预览里某行
created_at显示为NULL,但源库明明有值 - 执行后目标库该字段比源库早/晚 8 小时(比如源是
2026-04-21 15:00:00,目标写成2026-04-21 07:00:00) - 同步报错
Incorrect datetime value: 'NULL',尤其在STRICT_TRANS_TABLES模式下
这不是 Navicat bug,是它默认用系统本地时区发起连接,而你的服务器大概率跑在 UTC 或东八区,没对齐。
MySQL 连接高级设置里怎么填时区参数
必须进连接属性 → 「高级」页手动加参数,不能只靠系统时区。Navicat 16+ 不提供图形化时区下拉框,得填 serverTimezone。
实操建议:
- 对 MySQL 5.7 / 8.0,连接字符串末尾追加:
&serverTimezone=Asia/Shanghai&useTimezone=true - 如果连的是阿里云 RDS 或腾讯云 CDB,有些环境要求写成
&serverTimezone=GMT%2B8(%2B是 URL 编码的+) - 别只设
useTimezone=true—— 它不生效,必须配对serverTimezone - 改完要右键连接 → 「编辑连接」→ 重输密码才能让新参数加载(Navicat 缓存旧握手信息)
验证是否生效:连上后执行 SELECT @@time_zone, NOW(), SYSDATE();,三个结果应该都落在你预期的时区范围内。
PostgreSQL 连接为什么 set timezone='Asia/Shanghai' 每次重启就失效
因为 SET timezone = 'Asia/Shanghai' 只作用于当前会话,Navicat 新建连接就是新会话。你每次点开新查询窗口,都得重设一次。
真正持久的办法是改连接参数,不是写 SQL:
- PostgreSQL 连接 → 「高级」页 → 在「Initial statement」里填:
SET timezone = 'Asia/Shanghai'; - 注意结尾要带分号,否则 Navicat 解析失败
- 这个语句会在每次建立连接后自动执行,比手动
SET稳定得多 - 别用
SHOW timezone验证——它返回的是 session 设置,可能被中间件覆盖;用SELECT now();对比客户端显示更准
同步前还要检查哪些隐性时区陷阱
光设对连接时区还不够,表定义和 SQL mode 会二次干扰:
- 确认目标表字段定义含
NOT NULL DEFAULT CURRENT_TIMESTAMP,而不是NULL或没默认值——否则 Navicat 插入空值会被 MySQL 拒绝 - 查源库
SELECT @@sql_mode,如果含STRICT_TRANS_TABLES,同步时任何时间字段传NULL都会中断,且错误日志只标「1 warning」,得点开同步详情才能看到 - Navicat 同步脚本默认不带
SET time_zone = ...,所以即使连接设对了,生成的 SQL 文件里插入的字面量仍是客户端本地时间。若需完全可控,勾选「Generate synchronization SQL script」,手动在脚本开头加SET time_zone = 'Asia/Shanghai';
最易忽略的一点:不同环境的 explicit_defaults_for_timestamp 设置可能不一致,这会导致 TIMESTAMP 字段在没显式赋值时行为分裂——有的填当前时间,有的填 NULL,同步时悄无声息丢数据。











