乱码主因是客户端连接字符集与服务端不匹配,需确保character_set_client、connection、results三者一致且为utf8mb4;建表须显式指定character set utf8mb4;客户端连接参数优先级高于my.cnf配置。

查当前连接的字符集设置
乱码往往不是服务器全局设错了,而是客户端连上来时用了不匹配的编码。先确认你此刻连接用的字符集:SHOW VARIABLES LIKE 'character_set%'; 和 SHOW VARIABLES LIKE 'collation%';。重点看 character_set_client、character_set_connection、character_set_results 这三项——它们必须一致,且最好和表/列的 character_set 匹配。
常见错误现象:插入中文显示为问号(?)或 Mojibake(如“æäº›æ‡å”),但 SELECT HEX(col) 看到的是合法 UTF-8 字节序列,说明写入没问题,只是读取解码错了。
- 如果这三项不一致,说明客户端没正确声明编码,比如 Python 的
pymysql.connect()漏了charset='utf8mb4' - MySQL 8.0+ 默认用
utf8mb4,但老客户端(如某些 shell 或旧 JDBC 驱动)仍可能默认发latin1,导致服务端按 latin1 解析 UTF-8 字节 -
SET NAMES utf8mb4是临时补救,但它只改当前会话的 client/connection/results 三值,不能替代连接参数
建表与列级字符集必须显式指定
别依赖 CREATE DATABASE 时的默认值。MySQL 的默认字符集可能被配置文件覆盖,也可能因版本而异(5.7 默认 latin1,8.0 默认 utf8mb4),但表和列不会自动继承数据库默认值——除非你明确写了 DEFAULT CHARSET。
使用场景:迁移旧库、导入 SQL 文件、ORM 自动生成表结构时,容易忽略这一层。
- 创建表时务必加
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,例如:CREATE TABLE t (name VARCHAR(100)) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 已有表修改需用
ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;,注意这会重建表,大表慎用 - 只改列定义(如
MODIFY name VARCHAR(100) CHARACTER SET utf8mb4)不够,排序规则和索引前缀长度可能出问题
客户端连接参数比 my.cnf 更优先
很多人改完 /etc/mysql/my.cnf 里的 character-set-server=utf8mb4 就以为万事大吉,结果还是乱码。其实客户端驱动在建立 TCP 连接时,会主动发送初始字符集声明,这个声明直接覆盖服务端配置。
性能影响:错误的字符集声明不会拖慢查询,但会导致隐式转换,比如 WHERE name = '张三' 在 client=latin1、column=utf8mb4 时,MySQL 要把字符串从 latin1 转成 utf8mb4 再比较,索引可能失效。
- MySQL 命令行客户端加
--default-character-set=utf8mb4参数;或者在~/.my.cnf的[client]段写default-character-set = utf8mb4 - PHP mysqli:
$mysqli->set_charset('utf8mb4')必须在connect()后立刻调用 - Java JDBC URL 加
?characterEncoding=utf8mb4&useUnicode=true,注意是utf8mb4,不是utf8(MySQL 的utf8实际是 utf8mb3)
验证数据是否真乱码,还是显示层问题
终端、IDE、Web 页面显示异常,不等于数据本身损坏。先排除展示环节干扰,再动数据库。
容易踩的坑:用 SELECT 看到乱码就急着改表,结果发现是终端 locale 没设对,或者 HTML 没写 <meta charset="utf-8">。
- 用
SELECT HEX(col) FROM t LIMIT 1;查字段原始字节。正常中文 UTF-8 是 3 字节(如“中”→E4B8AD),如果看到3F3F3F(即多个?的 HEX),说明写入时就被替换成问号了 - Linux 终端检查
locale输出是否含UTF-8;Windows CMD 默认是 GBK,得用chcp 65001切换 - phpMyAdmin 或 DBeaver 等工具自身有字符集偏好设置,需单独确认,不能只信 MySQL 服务端返回值
C3A4C2B9C3BC),这种属于双重编码,恢复成本高,靠改配置解决不了。











