必须全链路统一为utf8mb4,包括客户端、连接、数据库、结果集和服务端五层字符集,缺一不可;生僻字需4字节支持,utf8mb3会静默截断致乱码或写入失败。

必须全链路统一为 utf8mb4,只改服务端或只改表结构都不行——生僻字(如「?」「?」)需要完整的 4 字节编码支持,MySQL 的 utf8(实为 utf8mb3)会静默截断第 4 字节,导致写入失败或显示为 ???。
确认当前五层字符集是否全部为 utf8mb4
生僻字乱码往往不是“没设”,而是某一层悄悄 fallback 到 utf8 或 latin1。执行:
mysql -e "SHOW VARIABLES LIKE 'character_set%';"
重点核对这 5 项是否全为 utf8mb4:
character_set_clientcharacter_set_connectioncharacter_set_databasecharacter_set_resultscharacter_set_server
只要其中一项是 utf8 或 latin1,生僻字就可能在解析、转换或返回环节被损坏。注意:character_set_filesystem 和 character_set_system 不影响业务数据,不用管。
修改 my.cnf 并重启 MySQL 服务
配置文件里光写 [mysqld] 段落不够,客户端工具(如 mysql 命令行、Navicat)也会读取自己的段落。必须同时覆盖三处:
- 在
[client]下加:default-character-set = utf8mb4 - 在
[mysql]下加:default-character-set = utf8mb4 - 在
[mysqld]下加:character-set-server = utf8mb4和collation-server = utf8mb4_unicode_ci
特别注意:skip-character-set-client-handshake = OFF 必须显式设置(不是默认值),否则客户端声明的 utf8 会覆盖服务端配置,导致握手降级。改完后务必重启:sudo systemctl restart mysqld,不能只重载配置。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
已有库表必须逐级 CONVERT TO,不能只改默认值
即使服务端已设 utf8mb4,旧表的列仍保留原始字符集。用 ALTER TABLE table_name CHARACTER SET utf8mb4 只改表默认值,不改列;真正生效的是:
- 改整个表(含所有文本列):
ALTER TABLE comments CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci - 只改某列(更安全,可控制范围):
ALTER TABLE comments MODIFY content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
执行前先查哪些列还没升级:SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_db' AND CHARACTER_SET_NAME != 'utf8mb4';。别跳过这步——很多乱码问题就出在某个 TEXT 列还是 utf8。
连接时必须显式声明 utf8mb4,不能依赖默认
应用代码里用 SET NAMES utf8 或 JDBC URL 里漏写 characterEncoding=utf8mb4,等于白配。常见语言写法:
- PHP PDO:
new PDO($dsn, $user, $pass, [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"]) - Python mysql-connector:
connect(..., charset='utf8mb4') - JDBC:
jdbc:mysql://host/db?characterEncoding=utf8mb4&serverTimezone=UTC
验证连接是否生效:连上后立刻执行 SELECT @@character_set_client, @@character_set_connection, @@character_set_results;,三者必须全为 utf8mb4。生僻字问题最常卡在这一步——配置全对,但连接一上来就走回 utf8 路径。
最容易被忽略的是:备份恢复和跨平台传输时,mysqldump 默认用 latin1 导出,即使源库是 utf8mb4,也会把生僻字变成乱码再存进 SQL 文件。导出必须加 --default-character-set=utf8mb4,导入前先执行 SET NAMES utf8mb4。这类损坏不可逆,修之前先确认备份文件本身是否已损坏。










