必须修改配置文件三处段落并重启验证,仅执行sql或改character-set-server无效;需在mysqld[mysql]段分别设置utf8mb4及相关校对规则,并alter已有库表,php连接仍需显式指定charset。

必须改配置文件,仅执行 SQL 命令或只改 character-set-server 无效。 MySQL 8.0 虽然官方默认是 utf8mb4,但 phpEnv、宝塔、Docker 默认镜像或 Windows MSI 安装包常沿用旧模板,my.ini 或 my.cnf 中实际未启用,导致新建库表仍用 utf8(即 utf8mb3)或 latin1,插入 emoji 直接报 Incorrect string value 错误。
修改 my.cnf / my.ini 的三处关键段落
MySQL 字符集生效依赖客户端、服务端、连接会话三层协同,缺一不可。不能只在 [mysqld] 段写 character-set-server=utf8mb4。
- 在
[mysqld]段添加:character-set-server = utf8mb4collation-server = utf8mb4_0900_ai_ci
(不要用utf8mb4_unicode_ci,MySQL 8.0 默认且更准) - 在
[client]段添加:default-character-set = utf8mb4
(影响所有客户端工具,如mysqldump、mysql命令行) - 在
[mysql]段添加:default-character-set = utf8mb4
(专用于mysql命令行客户端自身,不加可能被忽略)
Windows 用户注意路径:phpEnv 默认配置文件通常在 C:\phpEnv\MySQL\my.ini;宝塔用户请进【软件商店】→ MySQL → 【设置】→ 【配置修改】;Docker 用户必须挂载自定义 my.cnf 到容器内 /etc/mysql/my.cnf,且权限设为 644,否则静默跳过。
重启后必须验证四个变量全为 utf8mb4
只改配置不验证,等于没改。MySQL 连接层有四个核心变量决定实际行为,必须全部是 utf8mb4:
character_set_clientcharacter_set_connectioncharacter_set_resultscharacter_set_server
连接 MySQL 后执行:SHOW VARIABLES LIKE 'character%';
若其中任一值仍是 utf8 或 latin1,说明配置未加载(常见于配置写错段落、路径不对、或被 [mysqld_safe] 等冲突项覆盖)。Linux 下用 mysql -h 127.0.0.1 -u root -p 强制走 TCP 连接测试,避免 socket 连接绕过 [client] 段。
已有库表必须手动 ALTER,不会自动升级
character-set-server 只影响新创建的数据库和表,对已存在对象完全无效。老库老表字段即使存了 emoji,也仍是原字符集,查询时显示乱码或直接报错。
- 先改库:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci; - 再改每张表:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
(不能只用MODIFY COLUMN,它不重编码已有数据) - 最后检查 TEXT/VARCHAR 字段:utf8mb4 单字符最多占 4 字节,若原
VARCHAR(255)在 InnoDB 中可能触发Row size too large,需酌情缩短长度
PHP 连接时仍要显式指定 charset=utf8mb4,例如 PDO DSN 加 ;charset=utf8mb4,mysqli_connect 第五个参数传 MYSQLI_SET_CHARSET_NAME。否则即使服务端全对,PHP 层仍可能协商成 utf8。
init_connect='SET NAMES utf8mb4' 不是万能的
这个配置项只对普通用户连接生效,对 root 或具有 SUPER 权限的用户完全不触发——这意味着你用 root 登录后执行 SHOW VARIABLES 看到的会话变量,可能和应用连接的实际值不一致。
- 它无法修复已建立连接的字符集,只作用于新连接握手后第一句执行语句
- 某些 ORM(如旧版 Laravel Eloquent)或连接池中间件可能忽略该指令
- 搭配
caching_sha2_password认证插件时,若客户端未声明字符集,仍可能回退到旧行为
真正兜底的方式,是把字符集控制权从连接层上收到服务端和客户端配置文件里,而不是依赖运行时 SQL。这也是为什么必须同时配齐 [client]、[mysql]、[mysqld] 三段——它们各自负责不同环节,漏一个,emoji 就可能卡在半路。











