MySQL 8.0+ strict mode 导致 ThinkPHP 插入失败、认证失败、时间字段报错及字段名大小写异常,根本原因是 MySQL 8.0 加强了数据校验与协议规范;应分别通过调整 sql_mode、重置用户认证方式、修改表默认值、统一字段访问命名等方式解决。

MySQL 8.0+ strict mode 导致 ThinkPHP 插入失败
ThinkPHP 5.x/6.x 在 MySQL 8.0+ 默认开启的 STRICT_TRANS_TABLES 模式下,常报错:Incorrect integer value: '' for column 'xxx' at row 1 或 Data too long for column。这不是 ThinkPHP 的 bug,而是 MySQL 对空字符串、隐式类型转换、默认值缺失更严格了。
根本原因是:ThinkPHP 构建的 SQL(比如 insert())可能传入空字符串给 INT 字段,或未显式指定非空字段值,而旧版 MySQL 会自动转成 0 或截断,新版直接拒绝。
- 临时解决:在数据库连接配置中关闭严格模式(不推荐生产环境)——在
database.php的dsn后追加;sql_mode='' - 正确做法:修改 MySQL 全局或会话级
sql_mode,保留必要校验但移除严格插入限制,例如设为NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES→ 改成NO_ENGINE_SUBSTITUTION - 更稳妥:在 ThinkPHP 的
Db::connect()初始化后,执行一次Db::execute("SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION'")
ThinkPHP 6.1+ 连接 MySQL 8.0 报 Client does not support authentication protocol
这是 MySQL 8.0 默认使用 caching_sha2_password 认证插件,而老版本 PDO(尤其 PHP 7.2 及以下)不支持。现象是连接直接失败,日志里出现该错误信息。
不能靠升级 PHP(虽然 PHP 7.4+ 增加了部分支持),因为 ThinkPHP 底层仍走 PDO MySQL 驱动,兼容性取决于底层 libmysql 或 mysqlnd 版本。
立即学习“PHP免费学习笔记(深入)”;
- 首选方案:登录 MySQL,为应用用户重置认证方式:
ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'your_pass'; - 避免改全局 default_authentication_plugin(影响其他服务)
- 确认 PHP 编译时用的是 mysqlnd 而非 libmysql(
php -i | grep "mysqlnd"),mysqlnd 对新认证协议支持更好
ThinkPHP 时间字段写入 MySQL 8.0 报 Invalid default value for 'create_time'
MySQL 8.0 默认启用 NO_ZERO_DATE 和 NO_ZERO_IN_DATE,而 ThinkPHP 的模型如果定义了 protected $createTime = 'create_time'; 且数据库字段是 DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',就会触发该错误。
本质是 MySQL 拒绝零日期作为有效默认值,而 ThinkPHP 自动生成的时间填充逻辑没适配这个约束。
- 建表时改用
CURRENT_TIMESTAMP作默认值:create_time DATETIME DEFAULT CURRENT_TIMESTAMP - 若无法改表结构,在连接 DSN 中加入
;sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION(去掉NO_ZERO_DATE) - ThinkPHP 模型中显式设置时间值,避免依赖数据库默认:
$data['create_time'] = date('Y-m-d H:i:s');
MySQL 5.7 升级到 8.0 后 ThinkPHP 查询结果字段名大小写异常
MySQL 8.0 默认开启 lower_case_table_names=1,但字段名(column name)在结果集中受系统变量 lower_case_field_names 控制;某些 Linux 环境下该值为 0,导致 ThinkPHP 的 select() 返回的数组键名变成全小写(如 user_name → user_name 正常,但 UserName → username),破坏原有驼峰映射逻辑。
这不是 ThinkPHP 自身问题,而是 MySQL 客户端协议返回的元数据字段名被服务端强制小写了。
- 检查当前值:
SELECT @@lower_case_field_names;,若为 0,说明字段名大小写敏感 - ThinkPHP 中统一用小写字段名访问结果(
$res['user_name']),别依赖原始大小写 - 避免在 SQL 中用反引号包裹大驼峰字段名(如
`UserName`),这会让结果集键名变成带反引号的字符串,极难处理 - 如需保持字段原样,唯一可靠方式是升级到 ThinkPHP 6.3+ 并启用
pdo_attr => [PDO::ATTR_CASE => PDO::CASE_NATURAL](但仅对 PDO 有效,且依赖驱动支持)
最麻烦的不是配置本身,而是不同环境(开发用 macOS,测试用 CentOS,生产用 Docker)的 lower_case_field_names 值可能不一致,导致本地跑得通,上线就出错。务必在 CI 阶段校验该变量值,并统一建模约定。



















