必须将mysql连接层字符集显式设为utf8mb4,包括laravel配置中的charset、collation及pdo初始化命令,并同步配置mysql服务端、表结构、迁移文件、php环境及redis等周边组件,否则emoji和生僻字会乱码或报错。

你在Laravel项目中执行迁移时遇到 SQLSTATE[HY000]: General error: 1366 Incorrect string value,或者用户昵称里的“?”“??”存不进数据库,又或者某些生僻汉字显示为问号——这些都不是代码写错了,而是MySQL底层的utf8字符集根本没资格处理它们。
为什么Laravel默认用utf8mb4而不是utf8
从Laravel 5.4起,框架生成的迁移文件和config/database.php中默认指定的就是utf8mb4。这不是凭空加戏,而是因为MySQL官方早在5.5.3就引入utf8mb4,并在8.0版本将其设为默认字符集;Laravel作为现代PHP框架,必须对齐真实UTF-8标准,否则无法承载emoji、古汉字、数学符号等合法Unicode字符。
你如果手动把数据库连接配置改成'charset' => 'utf8',哪怕Laravel版本再新,也会立刻踩进历史陷阱:MySQL的utf8实际叫utf8mb3,它只认得U+0000–U+FFFF范围内的字符,而?(U+1F60A)、?(U+1FAD7)、?(U+20213)全在U+10000以上——直接被截断或报错。
三步确认你的Laravel项目是否真用了utf8mb4
第一步:检查config/database.php中MySQL配置块的charset和collation字段——必须同时为'utf8mb4'和'utf8mb4_unicode_ci'(或utf8mb4_0900_as_cs,MySQL 8.0+推荐)。
第二步:运行php artisan tinker,输入DB::connection()->getPdo()->getAttribute(PDO::ATTR_CLIENT_VERSION)确认PDO连接版本;再执行DB::select("SHOW VARIABLES LIKE 'character_set%';"),重点看character_set_database和character_set_server是否返回utf8mb4。
第三步:查一张已存在的表,运行SHOW CREATE TABLE users;(假设表名为users),观察CREATE TABLE语句末尾是否包含DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci——如果还是utf8,说明迁移没生效或建表时被覆盖。
迁移旧项目:从utf8升级到utf8mb4的实操路径
方法一:仅改连接配置(适用于全新项目或空库)
直接修改config/database.php里mysql配置项:'charset' => 'utf8mb4'、'collation' => 'utf8mb4_unicode_ci',并确保.env中DB_CHARSET=utf8mb4已设置。这一步生效的前提是数据库服务器本身支持utf8mb4且未被其他应用强制降级。
方法二:修改现有表结构(必须做,否则字段级仍卡在utf8mb3)
新建一个迁移文件:php artisan make:migration update_charset_to_utf8mb4,在up()方法中写入:
DB::statement("ALTER DATABASE `".config('database.connections.mysql.database')."` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci");
DB::statement("ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
⚠️ 注意:这里CONVERT TO会重写整张表数据,生产环境务必在低峰期执行,并提前备份。若表中有全文索引,需先删除再重建——因为utf8mb4下索引长度限制更紧(VARCHAR(255)在utf8mb4下最多占1020字节,超限会报错1071)。
方法三:字段级精准修复(适合大表或部分字段需保留utf8的场景)
不用CONVERT TO整表重写,逐个修改字段:
DB::statement("ALTER TABLE users MODIFY name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
DB::statement("ALTER TABLE users MODIFY email VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
这一步的关键是【必须同时指定CHARACTER SET和COLLATION,缺一不可】;只改字符集不改校对规则,MySQL可能回退到默认的latin1校对,导致排序异常。
连接层绕不过去的三个硬性条件
即使Laravel配置全对、表结构也改完了,只要下面任意一条不满足,utf8mb4照样失效:
① MySQL服务端配置my.cnf中必须包含:[client] default-character-set = utf8mb4、[mysqld] character-set-server = utf8mb4、collation-server = utf8mb4_unicode_ci,且重启MySQL服务生效。
② PHP的mysqlnd驱动版本不能低于5.0.9 —— 旧版驱动会静默忽略utf8mb4声明,强行降级为utf8。运行php -i | grep mysqlnd确认版本。
③ Laravel的DB_CONNECTION=mysql对应数据库用户的权限必须允许ALTER和CREATE——否则迁移执行到CONVERT TO时直接抛出权限错误,你以为是字符集问题,其实是账号没授权。











