MySQL服务器默认字符集需为utf8mb4以避免中文及emoji乱码,须检查并修改character_set_server、逐级转换库表列字符集、连接时显式指定charset=utf8mb4,并全流程验证。

确认 MySQL 服务器默认字符集是否为 utf8mb4
迁移后中文乱码,大概率是服务端默认字符集仍是 latin1 或旧版 utf8(即 utf8mb3),不支持四字节 Unicode 字符(如 emoji、部分生僻汉字)。utf8mb4 才是 MySQL 中真正兼容 UTF-8 的字符集。
执行以下命令检查:
SHOW VARIABLES LIKE 'character_set%';
重点关注:character_set_server 和 collation_server。若前者不是 utf8mb4,需修改配置文件(如 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf):
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
⚠️ 注意:仅改客户端配置(如 [client] 段)不能解决表/列存储层乱码,必须确保 character-set-server 生效且重启 mysqld。
检查并修正已有数据库、表、列的字符集
即使服务端默认设为 utf8mb4,迁移前创建的库/表/列仍可能沿用旧字符集,导致新数据写入正常、老数据读取乱码。
逐级检查并转换:
- 查库字符集:
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'your_db'; - 查表字符集:
SHOW CREATE TABLE your_table;或SELECT TABLE_NAME, TABLE_COLLATION FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db'; - 查字段字符集:
SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table' AND DATA_TYPE IN ('varchar', 'text', 'char', 'tinytext', 'mediumtext', 'longtext');
修正顺序必须是:库 → 表 → 列,否则 ALTER 可能失败或不生效:
ALTER DATABASE your_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
⚠️ 注意:CONVERT TO 会重写整张表,大表需评估锁表时间;若只需改列字符集(如只改某 varchar 字段),用 MODIFY COLUMN 更精准。
确保客户端连接时显式指定 charset=utf8mb4
很多应用(PHP PDO、Python pymysql、Java JDBC)即使服务端是 utf8mb4,若连接字符串没声明字符集,MySQL 仍可能按 latin1 解析请求,造成“存的是对的,取出来是问号”。
常见连接方式示例:
- PHP PDO:
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", $user, $pass); - Python pymysql:
conn = pymysql.connect(..., charset='utf8mb4') - JDBC URL:
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8mb4 - MySQL 命令行客户端:
mysql --default-character-set=utf8mb4 -u user -p
⚠️ 注意:JDBC 中 characterEncoding=utf8 是错的,必须写 utf8mb4;PDO 中 charset=utf8 同样无效,MySQL 会降级为 utf8mb3。
验证插入与查询全流程是否真正统一
光看配置不等于生效。最可靠的验证是模拟真实路径:插入含中文+emoji 的数据 → 退出客户端 → 用另一终端(或不同连接方式)查询,观察是否原样返回。
测试 SQL:
INSERT INTO test_table (content) VALUES ('测试✅'); SELECT content FROM test_table WHERE content LIKE '%测试%';
若返回 测试? 或 æµè¯â
,说明某环节仍卡在 utf8mb3 或 latin1;若返回 测试✅,再检查应用日志中是否有 Incorrect string value 报错(该错误明确表示客户端发来的四字节字符被服务端截断)。
容易被忽略的一点:MySQL 的 init_connect 系统变量如果设置了 SET NAMES latin1,会覆盖连接时的 charset 参数,务必检查并清空该配置。


















