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

MySQL 连接层字符集必须显式设为 utf8mb4
Laravel 默认用 utf8(实际是 MySQL 的 utf8,即最多 3 字节的伪 UTF-8),不支持 emoji 和部分中文生僻字,一存就变 ??? 或直接报错 SQLSTATE[HY000]: General error: 1366 Incorrect string value。
真正要改的是连接时的字符集,不是只改数据库或表的默认编码。
- 在
config/database.php的mysql配置块里,加'charset' => 'utf8mb4'和'collation' => 'utf8mb4_unicode_ci' - 同时必须加上
'options' => [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"],否则 Laravel 8+ 在某些 PDO 版本下仍可能走默认utf8 - 别只改
.env里的DB_CHARSET=utf8mb4—— 这个变量 Laravel 官方配置里根本没读,纯属误导
迁移前必须确认 MySQL 服务端已启用 utf8mb4 支持
哪怕 Laravel 连接层设对了,如果 MySQL 本身没配好,照样乱码。重点看三处:
-
my.cnf(Linux)或my.ini(Windows)里,[mysqld]段必须有:character-set-server = utf8mb4和collation-server = utf8mb4_unicode_ci - 重启 MySQL 服务后,进命令行执行
SHOW VARIABLES LIKE 'character_set%';,确认character_set_server和character_set_database都是utf8mb4 - 已有表和字段得手动升级:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;;只改表默认值不够,旧字段还是utf8
php artisan migrate 生成的表默认仍是 utf8,需强制覆盖
Laravel 的 Schema::create() 在 9.x 之前默认用 utf8 建表,即使你改了配置也不生效 —— 这是个长期被忽略的隐性行为。
- 在迁移文件里显式指定引擎和字符集:
Schema::create('posts', function (Blueprint $table) { ... });后追加DB::statement("ALTER TABLE posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); - 更稳妥的做法:在
AppServiceProvider::boot()中全局设置Schema::defaultStringLength(191);(避免索引长度超限),并确保所有新建迁移都用$table->string('title')->charset('utf8mb4');这类显式声明 - 别依赖
DB::connection()->getPdo()->exec("SET NAMES utf8mb4");—— 它只影响当前连接,对 migration 命令行进程无效
Redis 缓存、队列、日志中混入中文时也要防二次编码
字符集统一不只是数据库的事。比如用 Redis 存序列化后的模型,或队列任务里带中文参数,若底层 PHP 或扩展没处理好编码,取出来还是乱码。
- 检查
php.ini中default_charset = "UTF-8"是否开启(注意是双引号,且大小写敏感) - 用
json_encode($data, JSON_UNESCAPED_UNICODE)处理 API 返回,否则中文变\u4f60\u597d,前端再解也容易出错 - Log channel 写文件时,确保日志路径所在文件系统支持 UTF-8(比如 Windows 上用 NTFS 没问题,但某些挂载的网络盘可能默认 ASCII)
最麻烦的不是哪一步设错了,而是几处字符集设置互相覆盖又不报错 —— 比如 MySQL 服务端是 utf8mb4,PDO 连接设成 utf8,Laravel 迁移又按 utf8 建表,最后查出来看着像对,一存 emoji 就崩。这种组合问题,光看单点配置根本发现不了。











