先执行SELECT @@sql_mode确认是否由STRICT_TRANS_TABLES等严格模式导致写入失败,再结合报错信息锁定问题;临时用SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION'验证,永久修改需在[mysqld]段配置sql_mode并重启服务。

MySQL 8.0 升级后报错,八成是 sql_mode 默认变严格了,不是配置错了,也不是服务挂了——先别改配置,查清哪项在作怪。
怎么看当前 sql_mode 到底启用了哪些模式?
登录 MySQL 后直接执行:SELECT @@sql_mode;。重点盯输出里有没有这几个关键词:
-
STRICT_TRANS_TABLES:导致Field 'xxx' doesn't have a default value -
ONLY_FULL_GROUP_BY:触发ERROR 1055,比如SELECT id, name FROM t GROUP BY dept_id -
NO_ZERO_DATE或NO_ZERO_IN_DATE:让'0000-00-00'插入失败,报Incorrect datetime value -
ERROR_FOR_DIVISION_BY_ZERO:除零时不再警告,直接报错 1365
注意:@@sql_mode 查的是会话级值;要确认全局生效配置,得用 SELECT @@global.sql_mode;。
临时验证:只对当前连接绕过,不重启、不改配置
开发或测试环境快速试错,用 SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION'; 就够了。几个关键点:
- 必须写全值,不能留空:
SET SESSION sql_mode = ''在 8.0 会退回到默认严格模式 - 它只影响当前连接,断开重连就恢复原样,适合单条 SQL 排查
- 别在生产环境长期用这个命令“修复”,掩盖问题比报错更危险
永久修改:配置文件位置、格式、重启缺一不可
编辑 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf,只在 [mysqld] 段下加这一行:
sql_mode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"
这是 MySQL 5.7 的默认值,兼容老项目又保留基础校验。注意:
- 必须用双引号包裹整个值,中间不能有空格(MySQL 8.0 对格式敏感)
- 绝对不能写在
[client]或[mysql]下,那些段不控制服务端行为 - 改完必须重启服务:
sudo systemctl restart mysql,reload不生效 - 云数据库(如阿里云 RDS)通常禁用此配置,只能靠连接串参数或 init_command 动态设置
最常被忽略的覆盖源:ORM 和连接驱动
即使配置文件改对、服务也重启了,SELECT @@sql_mode 还可能显示不对——大概率是应用层在连接时悄悄重设了。排查方法:
- 检查代码里数据库初始化部分,比如 Peewee 的
sql_mode='TRADITIONAL'、Django 的OPTIONS={'init_command': 'SET sql_mode=...'} - Java JDBC URL 是否带
?sessionVariables=sql_mode=... - 开启 MySQL general_log:
SET GLOBAL general_log = 1;,复现一次写入,看日志里有没有SET sql_mode =这类语句
真正卡住人的从来不是怎么写配置,而是你改了三次 my.cnf,却没发现 Spring Boot 的 application.yml 里早有一行 spring.datasource.hikari.connection-init-sql: SET sql_mode='...'。











