mysql的utf8实为utf8mb3,仅支持3字节字符,无法存储emoji及部分生僻汉字;utf8mb4才是完整utf-8实现,需同步配置服务端、连接层与表结构三处,缺一不可。

默认用 utf8mb4,别碰 utf8 —— 后者在 MySQL 里根本不是真正的 UTF-8,存不了 emoji 和部分生僻汉字。
为什么 utf8 在 Laravel + MySQL 中不安全
MySQL 的 utf8 实际只支持最多 3 字节的字符(U+0000–U+FFFF),而标准 UTF-8 要求支持 4 字节(U+010000–U+10FFFF)。这意味着:
- 微信昵称里的 ?、?、? 会变成
???或直接报错Incorrect string value - 某些中文姓名(如「?」「?」)、古籍用字、数学符号无法写入
-
DB::insert()或 Eloquentsave()抛出异常,但错误信息不明确,容易误判为 SQL 语法问题
utf8mb4 配置要改全三处,缺一不可
只改 config/database.php 里的 charset 不够,MySQL 服务端、连接层、表结构必须同步生效:
-
config/database.php中对应连接的'charset' => 'utf8mb4'和'collation' => 'utf8mb4_unicode_ci'(推荐)或'utf8mb4_0900_as_cs'(MySQL 8.0+ 区分大小写) -
.env文件中显式设置:DB_CHARSET=utf8mb4(避免依赖 config 文件里的默认值) - MySQL 服务端配置(
my.cnf或mysqld.cnf)需包含:[client]<br>default-character-set = utf8mb4<br><br>[mysql]<br>default-character-set = utf8mb4<br><br>[mysqld]<br>character-set-server = utf8mb4<br>collation-server = utf8mb4_unicode_ci
已有数据表怎么安全升级到 utf8mb4
直接 ALTER TABLE 可能失败,尤其当字段含 TEXT 或有索引时。稳妥做法是:
- 先确认当前表字符集:
SHOW CREATE TABLE users;,观察DEFAULT CHARSET和各字段COLLATE - 对每个文本字段(
VARCHAR,TEXT)单独转换:ALTER TABLE users MODIFY name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 索引字段长度超限(如
VARCHAR(300)加了索引)会导致Specified key was too long错误,此时需先删索引、改字段、再重建索引 - 迁移文件中不要写
->charset('utf8mb4')—— Laravel 迁移不支持该语法;靠DB::statement()或手动执行 SQL 更可控
注意 collation 选型的实际影响
utf8mb4_unicode_ci 是兼容性最广的选择,但排序规则较宽松(比如 ñ 和 n 视为等价);如果业务要求严格区分(如多语言用户目录、法律文书系统),建议:
- MySQL 8.0+ 用
utf8mb4_0900_as_cs(accent-sensitive + case-sensitive) - 避免用
utf8mb4_bin:二进制比较虽严格,但中文排序会按 Unicode 码点排(非拼音/笔画),体验反直觉 - Eloquent 查询中若用
whereRaw("BINARY name = ?", [$name])临时强制区分,比全局换 collation 更轻量
真正麻烦的从来不是改配置,而是历史表字段没预留足够长度(VARCHAR(191) 是早期 Laravel 默认,因 utf8mb4 单字符占 4 字节,索引长度限制 767 字节),这类隐性约束最容易在上线后突然暴露。











