MySQL中文乱码根本原因是客户端、连接层、服务端三层字符集不一致且未统一为utf8mb4;需执行SHOW VARIABLES LIKE 'character_set%'确认character_set_client、connection、results全为utf8mb4,并同步配置my.cnf中[client]、[mysql]、[mysqld]三段,重启服务后验证。

MySQL 存中文乱码,不是表或库设错了字符集就能解决的——根本原因是客户端、连接层、服务端三者字符集没对齐,且大概率还混用了 utf8(即 utf8mb3)而非真正的 utf8mb4。
检查 character_set_client/connection/results 是否全为 utf8mb4
乱码最常发生在插入或查询时显示 ??? 或 æ‘们 这类 Mojibake,第一步不是改表,而是确认当前会话的三层编码是否一致:
- 执行
SHOW VARIABLES LIKE 'character\_set%';,重点看character_set_client、character_set_connection、character_set_results三个值 - 只要其中任意一个是
latin1、gbk或utf8(非utf8mb4),就必然出问题 - 即使
character_set_database和表定义都是utf8mb4,这三层不一致也会导致 SQL 解析或结果返回阶段丢字节
创建存储过程前必须 SET NAMES utf8mb4
存储过程体内的中文字符串(比如 SELECT '你好' 或注释)是在客户端发送 SQL 时就被解析的,如果连接初始用的是 latin1,那两个汉字会被按双字节截断存进 mysql.proc 表,后续怎么改都救不回来:
- 在执行
CREATE PROCEDURE前,显式加一句SET NAMES utf8mb4; - 如果是脚本批量导入,把
SET NAMES utf8mb4;放在第一行,别依赖配置文件 - 命令行客户端启动时加参数:
mysql --default-character-set=utf8mb4 -u root -p,比进库再SET更可靠
my.cnf 必须同时配 [client]、[mysql]、[mysqld] 三段
只在 [mysqld] 段写 character-set-server = utf8mb4 是无效的——它只影响新建库/表的默认值,不影响客户端怎么连进来:
-
[client]段控制所有客户端工具(如mysql、mysqldump)的默认字符集 -
[mysql]段专用于mysql命令行客户端,优先级高于[client] -
[mysqld]段设character-set-server和collation-server,但必须配合前两段才完整 - 改完必须重启 MySQL:
systemctl restart mysqld,reload不生效
ALTER TABLE CONVERT TO 要小心索引长度超限
已有表从 utf8 升级到 utf8mb4 时,CONVERT TO CHARACTER SET utf8mb4 会重建整张表,且可能因索引长度超标直接报错:
- InnoDB 旧版本单索引长度上限是 767 字节;
VARCHAR(255)在utf8mb4下最多占 1020 字节(255 × 4) - 报错
Specified key was too long时,不能硬改配置,应先缩短字段:ALTER TABLE t MODIFY c VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -
MODIFY比CONVERT TO更可控,不重建全文索引,也不动其他列定义 - 别漏掉
COLLATE:用utf8mb4_unicode_ci(或 MySQL 8.0+ 的utf8mb4_0900_as_cs),utf8mb4_general_ci已弃用
真正容易被忽略的是:你看到的“显示正常”,未必代表数据存对了。有些客户端(比如老版 phpMyAdmin)会自行转码掩盖问题,验证必须用 HEX(column_name) 看原始字节,或者导出 SQL 文件用编辑器查十六进制。


















