先执行 select @@sql_mode; 检查是否已启用严格模式,若返回值含 strict_trans_tables 则已启用;否则需通过修改 my.cnf 中 [mysqld] 段的 sql-mode 配置并重启服务永久启用,或用 set session/global sql_mode 临时设置。

检查当前 sql_mode 是否已启用严格模式
先确认现状,别一上来就改配置。执行 SELECT @@sql_mode; 或 SHOW VARIABLES LIKE 'sql_mode';,看返回值里有没有 STRICT_TRANS_TABLES —— MySQL 8.0+ 默认带这个,但只对新连接生效;如果返回空或只有 NO_ENGINE_SUBSTITUTION 这类非严格项,说明没真正启用。
永久启用:修改 my.cnf/my.ini 配置文件
这是最可靠的方式,避免连接池复用旧连接导致“改了没用”。编辑配置文件,在 [mysqld] 段下添加或修改:
sql-mode = "STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
注意几点:
-
STRICT_ALL_TABLES不要加——MyISAM 表出错无法回滚,反而造成数据不一致 -
ALLOW_INVALID_DATES必须排除,否则'2023-02-30'这种非法日期会被静默接受 - Docker 容器或云数据库(如阿里云 RDS)可能锁定全局配置,此时该方式无效,得走会话级补救
- 改完必须重启 MySQL 服务,
service mysql restart或systemctl restart mysqld
临时启用:SET SESSION / SET GLOBAL
适合调试或无法改配置的环境,但效果有限:
-
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';只影响当前连接,断开即失效 -
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES';影响后续所有新连接,但已有连接仍沿用旧值 - Laravel、Django 等框架常在连接建立后自动覆盖
sql_mode,所以光执行 SET 可能被 ORM 覆盖掉 - 验证是否生效:在同个连接里再查一次
SELECT @@sql_mode;,别只信命令行输出
PHP/Laravel 连接后 sql_mode 被重置怎么办
很多 PDO 驱动会在 connect 后发 SET sql_mode = '' 或按框架配置覆盖,导致你配的白搭。解决思路是绕过客户端干预:
- 优先在 MySQL 侧固化配置(my.cnf + 重启),让所有客户端统一服从
- 若不可行,可在 Laravel 的
config/database.php中禁用自动设置:'strict' => false,再配合会话级SET手动补上 - 绝对不要写类似
PDO::MYSQL_ATTR_INIT_COMMAND => "SET sql_mode=(SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES',''))"这种主动关严格模式的代码
真正麻烦的不是怎么开,而是不同层级(全局/会话/客户端驱动)的配置互相覆盖,且无明确报错提示——查 @@sql_mode 必须在应用实际使用的连接里执行,不能只在 MySQL CLI 里验证。











