报错 err 1067 是因 mysql 5.7 默认启用 no_zero_date 和 no_zero_in_date 严格模式,禁止零日期默认值;修复需修改配置文件 sql-mode 并重启服务,或调整字段定义为 current_timestamp 或合法最小日期。

直接说结论:报错 Err 1067 - Invalid default value for 'xxx' 不是语法写错了,而是 MySQL 5.7 默认启用 NO_ZERO_DATE 和 NO_ZERO_IN_DATE 严格模式,禁止 '0000-00-00' 或 '0000-00-00 00:00:00' 这类零日期作为默认值。修复必须从模式配置或字段定义两个方向入手,临时 SET 不解决问题。
为什么 DEFAULT '0000-00-00' 在 5.7 会直接报错
MySQL 5.6 允许零日期作为 DATETIME/TIMESTAMP 默认值,但 5.7 将其视为非法值——哪怕字段允许 NULL、哪怕表结构本身没其他问题。只要建表语句里出现零日期字面量,就触发 Err 1067。这不是数据插入时的校验,是 DDL 解析阶段就拒绝。
-
NO_ZERO_DATE:禁用'0000-00-00'作为DATE或DATETIME的默认值 -
NO_ZERO_IN_DATE:禁用含零年/月/日的时间字面量(如'0000-00-00 00:00:00') - 这两个选项在 5.6 中默认关闭,5.7 开启后成为默认 sql_mode 的一部分
改配置文件才是可靠解法
临时执行 SET SESSION sql_mode = ... 对 Navicat 导入、shell 脚本执行、应用连接池等场景基本无效——它们各自建立新会话,不继承你手动设置的 session 级配置。必须改配置文件并重启服务。
使用ydata-profiling(前身为pandas-profiling)生成全面的数据质量报告,包含相关性分析、缺失值模式和基数检测。导出交互式HTML仪表板和JSON摘要。
- Linux 下编辑
/etc/my.cnf或/etc/mysql/my.cnf,在[mysqld]段下添加:sql-mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" - Windows 下修改
my.ini同样位置;macOS 若无配置文件,需从/usr/local/mysql/support-files/my-default.cnf复制一份到/etc/my.cnf - 关键:不要写成
sql-mode="",清空模式会关闭所有严格检查,带来隐性风险 - 改完必须重启 MySQL:
sudo systemctl restart mysql(Linux)或通过服务管理器重启(Win/mac)
CURRENT_TIMESTAMP 也报错?注意 datetime 和 timestamp 的差异
在 DATETIME 字段上写 DEFAULT CURRENT_TIMESTAMP 是合法的,但必须满足两个条件:字段不能声明为 NOT NULL DEFAULT '0000-00-00 00:00:00' 这类冲突定义;且不能省略 DEFAULT 关键字直接写 CURRENT_TIMESTAMP。
- 错误写法:
dt datetime NOT NULL DEFAULT '0000-00-00 00:00:00' DEFAULT CURRENT_TIMESTAMP(双重 DEFAULT) - 正确写法一(推荐):
dt datetime DEFAULT CURRENT_TIMESTAMP(允许 NULL,自动填当前时间) - 正确写法二:
dt datetime NOT NULL DEFAULT '1000-01-01 00:00:00'(用合法最小日期替代零日期) -
TIMESTAMP字段支持DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,DATETIME在 5.7+ 也支持,但仅限单个CURRENT_TIMESTAMP作为默认值
迁移脚本里怎么快速修复零日期默认值
如果你手头是一堆从 5.6 导出的 SQL 文件,逐个改 '0000-00-00 00:00:00' 效率低。可以用 sed 或 perl 批量替换,但要注意别误伤数据内容。
- 安全替换命令(Linux/macOS):
sed -i '' "s/DEFAULT '0000-00-00 00:00:00'/DEFAULT CURRENT_TIMESTAMP/g" *.sql(macOS 加-i '',Linux 去掉引号) - 更稳妥的做法:把零日期替换成
'1000-01-01 00:00:00'(DATETIME 最小合法值),避免业务逻辑误判“当前时间” - 注意:如果字段是
TIMESTAMP且带ON UPDATE,优先保留原意,只改默认值部分,不要动更新逻辑
最易被忽略的是 explicit_defaults_for_timestamp 这个开关——它控制 NULL 插入是否能 fallback 到默认值,5.7 默认为 OFF。若旧代码习惯插 NULL 依赖自动填充,光调 sql_mode 不够,还得在配置里加 explicit_defaults_for_timestamp=1 并重启。










