首页/数据/数据库速查/sql_mode 常见模式与排错
SQL 语法52 条

sql_mode 常见模式与排错

sql_mode 决定严格程度与语法兼容:严格模式拒绝坏数据、ONLY_FULL_GROUP_BY 拒绝歧义分组、ANSI_QUOTES 改双引号语义。

数据库速查数据更新于 2026-10-13

sql_mode 是什么

sql_mode 是 MySQL 服务端的一组 SQL 行为开关,决定数据校验收多严、GROUP BY 是否允许歧义、双引号是字符串还是标识符。它解释的是「同一条 SQL 在不同实例上行为不同」这类问题:严格模式直接报错,宽松模式静默截断。默认取值随版本变化,5.7 升 8.0 时差异尤其明显。

基本信息

适用MySQL 5.7 / 8.0,MariaDB 项名相近但默认值不同
查看SELECT @@sql_mode; 与 SELECT @@GLOBAL.sql_mode;
作用域SESSION 仅当前连接,GLOBAL 对新连接生效
持久化写 my.cnf 的 [mysqld] 段,重启后仍生效

高频模式项含义

模式项开启后的效果关闭后的风险
STRICT_TRANS_TABLES事务表写入非法值直接报错超长或类型不符的数据被静默截断
ONLY_FULL_GROUP_BY查询列表与分组必须语义确定分组查询随机返回某一行的值
NO_ZERO_DATE拒绝 0000-00-00 这类日期零值日期继续写入,报表与统计出错
ERROR_FOR_DIVISION_BY_ZERO严格模式下除零报错除零结果静默变成 NULL
ANSI_QUOTES双引号变成标识符引用老代码双引号字符串全部报 1054
NO_ENGINE_SUBSTITUTION指定引擎不可用时报错静默替换成默认引擎,表属性不符预期

查看与调整

查看与调整
SELECT @@sql_mode;                      # 当前会话实际取值
SELECT @@GLOBAL.sql_mode;               # 全局默认值,新连接继承它
SET SESSION sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';  # 只影响本会话
SET GLOBAL sql_mode='STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY,NO_ZERO_DATE';  # 新连接生效
SHOW VARIABLES LIKE 'sql_mode';         # 与 @@sql_mode 交叉验证
-- my.cnf 持久化:[mysqld] 下写 sql_mode=...,重启后才是最终值

典型使用场景

  • 迁移前 diff 源库与目标库的 sql_mode,预判哪些 SQL 会因严格程度变化报错
  • 老系统升级 8.0 后分组查询大面积报错,确认是否 ONLY_FULL_GROUP_BY 引起
  • 数据修复窗口临时放宽会话级模式,避免修复语句被严格校验挡住
  • 排查「写入成功但值不对」,回看是否发生静默截断或隐式取零
  • 统一引号语义,减少跨库迁移时的语法差异
5.7 到 8.0 的默认值变化集中在新增 ONLY_FULL_GROUP_BY、移除 NO_AUTO_CREATE_USER、默认启用严格模式,逐项比对而不是整串照搬。
生产不要为了兼容老代码关闭严格模式:问题不会消失,只是被推迟到查询或对账时才暴露,届时修复数据的成本更高。

易错点

  • 整串复制别人的 sql_mode 到 my.cnf:会覆盖版本默认项,缺少 NO_ENGINE_SUBSTITUTION 等项导致引擎被静默替换
  • 只改 GLOBAL 就以为生效:已存在的连接仍用旧值,连接池也不会自动重连,需重连或重启应用
  • 开启 ANSI_QUOTES 前不评估存量 SQL:双引号字符串全部变成标识符引用,直接报 1054
  • 用 SET SESSION 改模式修完数据却不记回滚:会话结束即恢复原值,容易误判为配置已改好

数据来源与参考

  • MySQL 8.0 Reference Manual: Server SQL Modes

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌