根本原因是MySQL服务端默认字符集为utf8mb3,不支持4字节UTF-8字符;需同步配置服务端、表结构、Laravel连接参数及PHP扩展四者均为utf8mb4。
MySQL 服务端没开 utf8mb4 支持
报 1366 incorrect string value 的根本原因,是 mysql 服务端默认字符集仍是 utf8(实际是 utf8mb3),不支持 4 字节 utf-8 字符(比如 emoji、部分生僻中文、古汉字)。laravel 写入时用了 utf8mb4 连接配置,但服务端没配对应字符集和排序规则,就会在插入阶段被拦住。
实操建议:
- 检查 MySQL 当前默认字符集:
SHOW VARIABLES LIKE 'character_set%';,重点看character_set_server是否为utf8mb4 - 修改
my.cnf(Linux)或my.ini(Windows),在[mysqld]下加两行:character-set-server = utf8mb4<br>collation-server = utf8mb4_unicode_ci
- 重启 MySQL:不重启,改了配置也无效;
systemctl restart mysql或service mysqld restart - 注意:仅改客户端或连接层配置(如
init_connect)不能解决插入报错,必须服务端级生效
Laravel 数据库连接没指定 utf8mb4
即使 MySQL 已支持 utf8mb4,Laravel 的 config/database.php 若没显式声明,仍可能走默认 utf8 连接,导致握手时用错编码,后续 insert 依然失败。
实操建议:
- 确认
config/database.php中 MySQL 配置段含以下两项:'charset' => 'utf8mb4',<br>'collation' => 'utf8mb4_unicode_ci'
- 如果用的是 Laravel 5.4+,还要确保
'prefix' => ''后面没漏掉逗号导致语法错误——这个小问题会让整个配置加载失败,退回到框架默认值 - 运行
php artisan config:clear清缓存,否则改了配置也不生效 - 验证是否生效:在 Tinker 里执行
DB::connection()->getPdo()->getAttribute(PDO::ATTR_CLIENT_VERSION)和连接后的DB::select('SELECT @@character_set_database, @@collation_database')
已有表没转成 utf8mb4
旧表即使数据库默认字符集改了,本身还是 utf8,字段长度限制、索引长度(比如 VARCHAR(255) 在 utf8mb4 下实际占 1020 字节)都没变,插入长中文或 emoji 时仍会截断或报错。
实操建议:
- 逐个转换表:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 更稳妥的做法是只改字段(避免隐式转换出错):
ALTER TABLE users MODIFY name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 注意索引限制:InnoDB 单列索引最大 767 字节(
utf8mb4下最多支持约 191 个字符),若原字段是VARCHAR(255)且建了索引,得先DROP INDEX,再MODIFY,最后重建索引 - 别跳过迁移文件里的
DB::statement()手动 SQL —— Schema 构建器对字符集转换支持有限,尤其带外键或全文索引的表
PHP PDO 驱动版本太低或编译参数缺失
极少数情况下,PHP 的 pdo_mysql 扩展编译时没启用 --with-mysql-sock 或链接了旧版 MySQL 客户端库,会导致即使配置全对,连接时仍协商成 utf8 编码。
实操建议:
- 检查
php -i | grep -i mysql输出中的mysqlnd版本,低于5.0.12的老版本有已知编码协商 bug - 确认
pdo_mysql.default_socket指向正确的 socket 文件(尤其 MAMP/MAMP Pro 用户常在这里出错) - 临时验证方法:在
.env中加MYSQL_ATTR_INIT_COMMAND="SET NAMES utf8mb4"(需在database.php的options数组里透传),但这只是补丁,不是根治 - 容器环境(Docker)要特别注意 base image 的 MySQL 客户端版本,
php:8.2-cli默认带较新驱动,但自定义 Alpine 镜像容易踩坑
真正卡住人的,往往不是某一个配置点,而是「MySQL 服务端 + 表结构 + Laravel 连接参数 + PHP 扩展」四者中有一环没对齐。尤其是上线后才改字符集,旧数据迁移和索引重建那步最容易漏测。


















