根本原因是mysql连接层字符集未设为utf8mb4,必须在laravel配置中同时设置charset、collation及pdo初始化命令,并同步修改mysql服务端、表结构、迁移文件、php和redis等全链路组件。

Laravel项目存emoji或生僻中文时变成???、报错SQLSTATE[HY000]: General error: 1366 Incorrect string value,根本原因不是数据库建表编码没改,而是MySQL连接层字符集仍走默认utf8(即最多3字节的伪UTF-8),必须强制设为utf8mb4并穿透到PDO初始化命令中,否则任何表结构修改都无效。
配置Laravel连接层字符集
打开config/database.php,定位到'mysql'配置块,在其中添加或修改三项:
【charset和collation必须同时设为utf8mb4】只改其中一个会导致PDO连接时校验失败。
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'options' => [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"],
注意:别只改.env里的DB_CHARSET=utf8mb4——Laravel官方配置根本不读这个变量,纯属误导。
确认MySQL服务端已启用utf8mb4
这一步漏掉,前面所有配置都会失效。编辑my.cnf(Linux)或my.ini(Windows),在[mysqld]段落里加入:
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
重启MySQL服务后,执行mysql -u root -p进入命令行,运行:
SHOW VARIABLES LIKE 'character_set%';
重点检查character_set_server和character_set_database两项输出值是否均为utf8mb4。如果不是,说明配置未生效或未重启服务。
升级已有表与字段编码
已有数据表不会自动继承新配置,必须手动转换:
第一步:执行ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
第二步:单独处理TEXT/BLOB类型字段(如content),因为CONVERT TO可能不覆盖它们:
ALTER TABLE posts MODIFY content LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
第三步:检查索引长度——utf8mb4下VARCHAR(255)的索引会超限,需提前在AppServiceProvider::boot()中加:Schema::defaultStringLength(191);
迁移文件中强制指定字符集
Laravel 9.x之前版本的Schema::create()默认用utf8建表,即使你改了全局配置也不生效。必须在迁移文件里显式声明:
方法一:在Schema::create()之后追加原生SQL
DB::statement("ALTER TABLE posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
方法二:对每个字符串字段单独指定(更稳妥)
$table->string('title')->charset('utf8mb4');
$table->text('body')->charset('utf8mb4');
注意:别依赖DB::connection()->getPdo()->exec("SET NAMES utf8mb4")——它只影响当前连接,对migration命令无效。
验证PHP环境与Redis同步
如果应用用了Redis缓存中文或emoji,也要统一字符集:
在config/database.php的redis配置块中,确保'options' => ['prefix' => 'laravel_database:']后追加'charset' => 'utf8mb4'(部分Redis客户端支持);
更关键的是PHP自身:确认phpinfo()中default_charset为UTF-8,且mb_internal_encoding()返回UTF-8;
若使用PDO,检查pdo_mysql.default_socket路径是否正确——错误路径会导致连接回退到socket模式,绕过host/port配置,进而跳过字符集设置。











