mysql中文乱码根本原因是character_set_client、connection、results、表字段、连接字符串五者未全部对齐为utf8mb4;必须运行show variables like 'character_set%'确认三变量全为utf8mb4,改表需用convert to,连接字符串必须显式声明charset=utf8mb4。

乱码不是数据库“不支持中文”,而是字符集链路断在了某一处——character_set_client、character_set_connection、character_set_results、表字段、连接字符串,五者必须全部对齐为 utf8mb4,缺一不可。
查清当前会话真实字符集配置
别信建库语句或配置文件,运行时可能被覆盖。连上 MySQL 后立刻执行:
SHOW VARIABLES LIKE 'character\_set%';
重点关注这三项是否全为 utf8mb4:
-
character_set_client:你发 SQL 时,MySQL 认为你用的编码 -
character_set_connection:连接层转码用的中间编码,必须和 client 一致 -
character_set_results:返回结果时用的编码
只要有一个是 latin1 或 utf8(注意不是 utf8mb4),就说明链路已断。此时即使表定义是 utf8mb4,插入也会变成 ??? 或 \xE6\x88\x91 这类字节序列。
改表字段必须用 CONVERT TO,不能只改 DEFAULT CHARSET
ALTER TABLE table_name CHARACTER SET utf8mb4 只改元数据,字段实际存储仍按旧编码,无效。
真正生效的是:
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
但要注意:
- 大表会锁表、重建索引、临时磁盘空间翻倍,务必选低峰期
- 若字段有全文索引,
utf8mb4下单列索引长度上限是 767 字节,需配合innodb_large_prefix=ON和ROW_FORMAT=DYNAMIC - 只想改某列(比如
TEXT类型),用MODIFY更可控:ALTER TABLE t MODIFY content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
但必须重写完整字段定义,否则可能丢NOT NULL或DEFAULT约束
连接字符串必须显式声明 charset=utf8mb4
即使数据库、表、字段全设成 utf8mb4,只要应用连接没声明字符集,MySQL 仍按 latin1 解析请求——这是最常被忽略的一环。
不同场景写法不同:
- PHP PDO:
mysql:host=localhost;charset=utf8mb4必须写进 DSN - Java JDBC:
jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8mb4,注意&要转义,驱动建议用 8.0+ - 命令行
mysql客户端:mysql --default-character-set=utf8mb4 -u root -p,否则默认用latin1 - Navicat:右键连接 →「编辑连接」→「高级」→ 勾选「使用 MySQL 字符集」并选
utf8mb4
SET NAMES utf8mb4 不能替代连接字符串配置——它只影响当前会话变量,前提是连接建立时底层已支持 utf8mb4。如果驱动按 latin1 解析初始握手包,后续再 SET 也晚了。
SQL Server 插入中文乱码要区分字段类型
如果是 varchar 字段,插入中文必须加前缀 N:
INSERT INTO table_name (col) VALUES (N'中文');
否则会被当作单字节字符处理,存成 ???。
更彻底的解法是把字段改为 nvarchar,并确保:
- 数据库排序规则(
COLLATION)支持中文,如Chinese_PRC_CI_AS - 存储过程参数类型也同步改为
nvarchar - 建表时若仍用
varchar,需显式指定排序规则:CREATE TABLE test (a VARCHAR(255) COLLATE Chinese_PRC_CS_AS_WS);
SQL Server 的乱码问题往往卡在“是否用了 N 前缀”和“字段是否为 nvarchar”这两点上,而不是服务端全局配置。
最容易被忽略的其实是连接层:charset=utf8mb4 漏掉,前面所有操作都白搭;SQL Server 里漏掉 N 前缀,nvarchar 字段也照样存成问号。










