生产环境禁用 mysql 8.0 严格模式必须修改 my.cnf 中 [mysqld] 段的 sql_mode 配置并重启服务,set global 仅临时生效且重启即失效;需确认 @@global.sql_mode 不含 strict_trans_tables、strict_all_tables 或 only_full_group_by。

生产环境禁用 MySQL 8.0 严格模式,不能靠 SET GLOBAL 临时改,必须修改配置文件并重启服务——否则下次滚动更新、节点重启或容器重建,sql_mode 就自动恢复默认值,故障重现。
确认当前 sql_mode 是否含 STRICT 或 ONLY_FULL_GROUP_BY
登录 MySQL 后执行:SELECT @@GLOBAL.sql_mode;
重点检查返回值里是否包含:STRICT_TRANS_TABLES、STRICT_ALL_TABLES 或 ONLY_FULL_GROUP_BY。只要出现任意一个,就说明严格行为已启用。
常见报错直接对应这些模式:
-
Field 'xxx' doesn't have a default value→STRICT_TRANS_TABLES -
Expression #1 of SELECT list is not in GROUP BY clause→ONLY_FULL_GROUP_BY -
Data too long for column或截断静默失败变报错 →STRICT_TRANS_TABLES
永久修改 my.cnf(仅在 [mysqld] 段生效)
编辑配置文件(Linux 常见路径:/etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf;macOS 可能是 /usr/local/mysql/my.cnf;Windows 是 my.ini),确保操作在 [mysqld] 段内:
✅ 推荐写法(保留基础安全项,移除严格项):sql_mode = "NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO"
⚠️ 必须避免的错误:
- 写成
sql-mode = ...(带连字符,MySQL 8.0+ 不识别) - 把配置写在
[client]或[mysql]段下(完全无效) - 设为空字符串:
sql_mode = ""(MySQL 8.0.19+ 会拒绝启动,报错Invalid sql_mode) - 用单引号包裹值(部分旧版本解析失败,统一用双引号)
重启服务并验证是否真正生效
配置改完不重启等于没改。必须执行对应命令重启 mysqld 进程:
- Linux(systemd):
sudo systemctl restart mysql(或mysqld,取决于服务名) - macOS(Homebrew 安装):
brew services restart mysql - Windows:
net stop MySQL80 && net start MySQL80(服务名以实际为准)
重启后立刻验证:SELECT @@GLOBAL.sql_mode;
输出中不应再出现 STRICT_* 或 ONLY_FULL_GROUP_BY。再试一条曾报错的 SQL(比如向 NOT NULL 列插 NULL),确认不再报错。
Docker 环境特别注意:挂载的配置文件路径是否正确?docker exec -it mysql cat /etc/my.cnf 看到的是否是你改的那一份?本地测试通过但线上失效,八成是容器没读到新配置。
为什么不能只依赖 SET GLOBAL?
SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION'; 看似快,但在生产中是危险操作:
- 只影响之后新建的连接,已有长连接(如应用连接池里的活跃连接)仍按旧模式运行
- MySQL 重启后立即还原为配置文件定义的值,无人值守重启即回退
- 云数据库(如阿里云 RDS、AWS RDS)通常禁用
SET GLOBAL权限,命令直接报错Access denied
更隐蔽的问题:某些中间件(如 ProxySQL、ShardingSphere)会复用连接或透传 session 设置,导致行为不一致。配置文件是唯一可审计、可版本化、可灰度发布的控制点。











