mysql字符集配置需三段齐备:[client]、[mysql]、[mysqld]均设utf8mb4,php连接须显式指定charset,建库建表需手动声明字符集,索引字段长度受限于767字节(推荐varchar(191))。

MySQL 配置文件必须三段都写 utf8mb4
只改 [mysqld] 段,character-set-server = utf8mb4 是不够的。客户端工具(Navicat、DBeaver)、命令行 mysql、PHP 连接驱动,各自读取不同配置段,漏掉任一段都会导致连接层用回 latin1 或 utf8(即 utf8mb3)。
必须在 my.ini(Windows)或 my.cnf(Linux/macOS)中同时配置:
-
[client]段加default-character-set = utf8mb4—— 影响所有客户端库(含 PHP 的 mysqlnd) -
[mysql]段加default-character-set = utf8mb4—— 专用于mysql命令行客户端 -
[mysqld]段加character-set-server = utf8mb4和collation-server = utf8mb4_unicode_ci(MySQL 5.7)或utf8mb4_0900_ai_ci(MySQL 8.0)
改完必须重启 MySQL 服务。不重启,SHOW VARIABLES LIKE 'character_set_server' 看起来对,但连接层仍走旧值。
PHP 连接时 charset 必须显式写进 DSN 或调用 set_charset
PHP 的 mysqli 和 PDO 不会自动读取 MySQL 配置文件里的字符集设置。即使 my.cnf 全配对了,PHP 默认仍按 latin1 发起连接 —— 这是静默失败的根源。
正确做法:
- 用
PDO:DSN 中必须带charset=utf8mb4,例如:mysql:host=localhost;dbname=test;charset=utf8mb4;不能只靠options或charset配置项 - 用
mysqli:连接成功后第一句必须是$mysqli->set_charset('utf8mb4');mysqli_options($link, MYSQLI_SET_CHARSET_NAME, 'utf8mb4')不保证生效,别用 - ThinkPHP 5.1 等框架:删掉
database.php里的'charset' => 'utf8mb4',它在 DSN 存在时被忽略;只靠 DSN 字符串控制
验证是否真生效:连上后立即执行 SELECT @@character_set_client, @@character_set_connection, @@character_set_results,三个结果都得是 utf8mb4。
建库建表语句里 CHARACTER SET 不能省
MySQL 服务端和连接层都设对了,不代表数据能存进去。新建数据库如果不显式指定字符集,哪怕 character-set-server 是 utf8mb4,也可能继承旧默认(比如 latin1_swedish_ci);已有表更不会自动升级。
操作建议:
- 创建数据库:
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 创建数据表:必须在
CREATE TABLE末尾写全ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci - 已有表升级:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;注意该语句会重写整张表,大表慎用
别信“改了配置就自动同步”。SHOW CREATE TABLE tbl_name 输出里没看到 DEFAULT CHARSET=utf8mb4,说明还没真正生效。
utf8mb4 的索引长度限制容易被忽略
这是上线前最常踩的坑:字段定义为 VARCHAR(255) 并加了索引,MySQL 8.0 下直接报 Specified key was too long。
原因:InnoDB 单列索引默认上限 767 字节,utf8mb4 按每字符 4 字节预留空间,255 × 4 = 1020 > 767。
安全方案:
- 把索引字段长度缩到
VARCHAR(191)(191 × 4 = 764 ≤ 767) - 或启用大前缀支持:
innodb_large_prefix = ON+ 表选项ROW_FORMAT = DYNAMIC(MySQL 5.7+ 默认开启,但旧表可能未应用)
这个限制只影响索引,不影响存储本身 —— VARCHAR(255) 字段依然能存满 255 个 emoji,但你不能给它建普通索引。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











