MySQL 8.0升级后报错主因是sql_mode默认变严格,含ONLY_FULL_GROUP_BY、STRICT_TRANS_TABLES、NO_ZERO_IN_DATE等,需通过SELECT @@sql_mode确认,临时用SET SESSION调整,永久修改须在[mysqld]段配置并重启,根本解法是修复表结构与SQL写法。

MySQL 8.0 升级后报错,八成是 sql_mode 默认值变了,不是配置写错了,也不是SQL写崩了——是 MySQL 主动“较真”了。
为什么刚升级就满屏报错?
MySQL 8.0 默认启用了更严格的 sql_mode 组合,核心变化有三处:
-
ONLY_FULL_GROUP_BY:导致SELECT a, b, COUNT(*) FROM t GROUP BY a这类查询直接报错,因为b既没聚合也没进GROUP BY -
STRICT_TRANS_TABLES强化版:原来能插入的空值、超长字符串、零日期('0000-00-00'),现在全被拦住,报Field 'xxx' doesn't have a default value或Incorrect datetime value -
NO_ZERO_IN_DATE和NO_ZERO_DATE新增:老项目里用0000-00-00当占位符的逻辑会立刻失败
这些不是 bug,是 MySQL 在强制你面对数据质量与语义确定性问题。查当前模式用:SELECT @@sql_mode;,别猜,直接看。
临时救火:会话级快速绕过
生产突发报错时,优先用会话级调整止损,不影响其他连接:
- 去掉
ONLY_FULL_GROUP_BY:SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY','')); - 关掉严格插入但保留其他校验:
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';(注意:别写空字符串,否则 MySQL 会自动补回默认集) - 允许零日期(仅当业务强依赖):
SET SESSION sql_mode = REPLACE(REPLACE(@@sql_mode,'NO_ZERO_IN_DATE',''),'NO_ZERO_DATE','');
⚠️ 所有 SET SESSION 命令只对当前连接有效,断开重连即失效;不要在应用代码里每条 SQL 前都加这个,而是统一在连接池初始化时执行一次。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
永久生效:my.cnf 配置必须写对位置和内容
想一劳永逸,得改配置文件,但常见踩坑点极多:
- 必须写在
[mysqld]段下,不是[client]或[mysql];否则完全不生效 - 不能只写
sql_mode = ""—— MySQL 8.0 会无视空值并恢复默认集;必须显式列出你要的项,例如:sql_mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY" - 已废弃的模式如
NO_AUTO_CREATE_USER写进去会导致 mysqld 启动失败,日志报Unknown or incorrect sql_mode - 改完必须重启服务:
systemctl restart mysqld,reload不生效 - 验证是否生效,查全局值:
SELECT @@global.sql_mode;(注意不是@@session)
云数据库(如阿里云 RDS)通常禁用 my.cnf 修改,得走控制台「参数模板」或 JDBC 连接串末尾加 ?sessionVariables=sql_mode=...。
真正该做的:别绕开,去修复
长期靠调 sql_mode 兼容旧逻辑,等于把数据风险外包给 MySQL 的宽容度。实际应做三件事:
- 对报
Field 'xxx' doesn't have a default value的表字段,补默认值:ALTER TABLE user MODIFY COLUMN phone VARCHAR(20) DEFAULT '';或改可空:MODIFY COLUMN phone VARCHAR(20) NULL; - 重写 GROUP BY 查询:要么把所有非聚合列加进
GROUP BY,要么用MAX(name)、ANY_VALUE(name)显式声明取值策略(ANY_VALUE需确认已启用sql_mode中含ONLY_FULL_GROUP_BY才有效) - 替换零日期:应用层把
'0000-00-00'改成NULL或合法占位如'1970-01-01',再配合字段设为NULL或加DEFAULT '1970-01-01'
最易被忽略的一点:ORM 自动生成的 SQL(比如 Django 的 .values('x').annotate(...))可能隐含非确定字段,这类问题不会出现在你写的原生 SQL 里,但会在上线后突然爆发。










