应精准移除strict_trans_tables、only_full_group_by、no_zero_date、no_zero_in_date、error_for_division_by_zero等破坏兼容性项,保留no_engine_substitution等基础校验;通过select @@sql_mode查当前模式,区分@@session.sql_mode(会话级)与@@global.sql_mode(全局级),临时调试用set session sql_mode=...剔除指定项,生产环境须在[mysqld]段配置sql_mode并重启生效。

直接结论:别清空 sql_mode,而是精准移除破坏兼容性的几项——STRICT_TRANS_TABLES、ONLY_FULL_GROUP_BY、NO_ZERO_DATE、NO_ZERO_IN_DATE、ERROR_FOR_DIVISION_BY_ZERO,保留 NO_ENGINE_SUBSTITUTION 等基础校验项。
怎么查当前严苛模式在哪儿生效?
先确认问题根源,不是所有报错都该改 sql_mode。连上 MySQL 执行:
SELECT @@sql_mode;
输出里如果含 STRICT_TRANS_TABLES(字段没值就插不进)、ONLY_FULL_GROUP_BY(GROUP BY 字段漏写)、NO_ZERO_DATE(插 '0000-00-00' 失败),就是它在作祟。注意区分:
-
@@session.sql_mode是当前连接生效的,适合调试 -
@@global.sql_mode是新连接默认用的,改了才影响全局
临时绕过(开发/测试环境快速验证)
会话级修改不重启、不改配置,但断开重连就失效,只用于定位问题:
SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
上面这行是错的——它反而保留了严苛项。正确写法是显式剔除:
SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION';
或者更安全一点,只去掉最常触发报错的几项:
SET SESSION sql_mode = (SELECT REPLACE(REPLACE(REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES,', ''), 'ONLY_FULL_GROUP_BY,', ''), 'NO_ZERO_DATE,', ''));
常见坑:
- 执行后必须重新执行
SELECT @@sql_mode验证,别信“执行成功”就完事 - 某些云数据库(如阿里云 RDS)禁止
SET GLOBAL,SET SESSION也受限,得走控制台参数模板
永久生效(生产环境必须这么做)
编辑 MySQL 配置文件(/etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf),在 [mysqld] 段下写:
sql_mode = "NO_ENGINE_SUBSTITUTION"
别写成 sql_mode = ""——MySQL 会自动补回默认值,ONLY_FULL_GROUP_BY 还在。关键点:
- 必须写在
[mysqld]下,写在[client]或[mysql]里无效 - 改完必须
systemctl restart mysqld,systemctl reload mysqld不生效 - 重启后查
SELECT @@global.sql_mode,不是@@session - 云数据库用户请去控制台找“参数模板”,手动改配置文件不起作用
为什么不能直接关掉所有校验?
清空 sql_mode 看似一劳永逸,但代价是隐式错误全放行:
- 插入超长字符串被静默截断,数据丢失不报警
-
INSERT INTO t(a) VALUES()往NOT NULL字段插NULL,变成0或空字符串,业务逻辑错乱 - 除零运算返回
NULL而非报错,下游计算结果不可靠
真正该做的,是把 STRICT_TRANS_TABLES 和 ONLY_FULL_GROUP_BY 这类“拦住旧 SQL”的开关关掉,但留着 NO_ENGINE_SUBSTITUTION 防止引擎降级、ONLY_FULL_GROUP_BY 关掉后仍要检查 GROUP BY 语义是否合理——这些细节,比改配置更容易被忽略。











