根本原因是MySQL服务端、Laravel连接层、已有表结构、迁移文件四层字符集未统一为utf8mb4;需依次配置MySQL服务端utf8mb4、修改database.php连接参数、升级旧表字段、迁移中指定InnoDB与utf8mb4。

部署Laravel项目时数据库存中文变问号、emoji报错SQLSTATE[HY000]: General error: 1366 Incorrect string value,根本原因不是代码写错了,而是MySQL服务端、Laravel连接层、已有表结构、迁移文件四层字符集配置未全部对齐为utf8mb4,漏掉任意一环都会导致数据写入即损坏。
确认MySQL服务端已启用utf8mb4
这一步不完成,后面所有Laravel配置都白搭。Laravel连得再对,MySQL底层不认utf8mb4照样丢数据。
打开MySQL配置文件(Linux为/etc/my.cnf或/etc/mysql/my.cnf,Windows为my.ini),在[mysqld]段落里添加两行:
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
保存后重启MySQL服务:sudo systemctl restart mysql(Ubuntu/Debian)或sudo service mysqld restart(CentOS)。重启后进MySQL命令行执行:SHOW VARIABLES LIKE 'character_set_server';,确认返回值是utf8mb4。如果还是utf8,说明配置路径错误或没重启。
修改Laravel连接层字符集
仅改.env里的DB_CHARSET=utf8mb4无效——Laravel官方代码根本没读这个变量,纯属误导。
打开config/database.php,找到mysql配置块,在其中显式设置三项:
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'options' => [
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
]
【PDO初始化命令不可省略】。没有这行,Laravel 8+在某些PDO版本下仍会走默认utf8连接,emoji存进去直接变???。
重建已有表和字段的字符集
已有表不会自动继承新连接配置,必须手动升级。只改表默认字符集不够,旧字段仍是utf8。
方法一:单表快速转换(适合小表)
在phpMyAdmin或HeidiSQL中执行:ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
方法二:逐字段指定(精准控制,推荐)
对关键字段如title、content执行:ALTER TABLE posts MODIFY title VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
【MODIFY会锁表,大表慎用】。
方法三:迁移文件中补救(适用于后续维护)
新建迁移:php artisan make:migration update_users_table_charset,在up()里写:DB::statement("ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
强制Laravel迁移使用InnoDB与utf8mb4
新Laravel项目执行迁移后表仍用MyISAM引擎,导致外键失效、全文索引不可靠、事务不支持,根本原因是MySQL服务端默认存储引擎未被覆盖,且字符集配置与引擎要求不匹配。
第一步:修改MySQL配置文件,在[mysqld]段落下添加:default-storage-engine = InnoDB;
第二步:编辑迁移文件,在Schema::create()闭包内添加三行:
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
【charset和collation必须同时设置,只设charset不生效】。
第三步:验证迁移结果是否真正落地——运行php artisan migrate后,立即执行:SHOW CREATE TABLE users;,检查建表语句末尾是否有ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci。


















