查清当前字符集和排序规则需先执行SHOW VARIABLES命令查看server级设置,再查INFORMATION_SCHEMA确认库表实际字符集;改库仅影响新建表,默认值需用ALTER DATABASE,改表须用ALTER TABLE CONVERT TO;客户端连接必须显式指定utf8mb4,且三个会话变量均需为utf8mb4。

查清当前字符集和排序规则
很多问题其实不是改了就完事,而是根本没搞清楚现在到底是什么状态。直接执行 SHOW VARIABLES LIKE 'character_set%' 和 SHOW VARIABLES LIKE 'collation%',重点看 character_set_server、collation_server 这两项——它们决定新建库的默认值,但对已有库表完全没影响。
更关键的是查具体库和表:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'your_db_name';SELECT TABLE_NAME, TABLE_COLLATION FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db_name';
- 如果
TABLE_COLLATION是utf8mb4_0900_ai_ci(MySQL 8.0+ 默认)或utf8mb4_unicode_ci,说明表本身已是 utf8mb4 - 如果显示
utf8_general_ci或latin1_swedish_ci,那数据可能存不全 emoji 或生僻汉字 - 注意:
utf8在 MySQL 里其实是utf8mb3,最多只支持 3 字节字符,别被名字骗了
ALTER DATABASE 和 ALTER TABLE 的实际写法
改库只是改默认值,不影响现有表;改表才是动真格的。必须分两步,且顺序不能反:
- 先改库默认字符集:
ALTER DATABASE your_db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - 再逐个改表:
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CONVERT TO 会重写所有字段的字符集和排序规则,并尝试转换已有数据。如果字段定义里写了 CHARACTER SET latin1,这一步能覆盖掉;但如果字段是 VARCHAR(255) CHARACTER SET utf8,它也会一并升级到 utf8mb4。
⚠️ 容易踩的坑:
– 不要用 MODIFY COLUMN 单独改某个字段,容易漏掉索引、约束或生成列
– CONVERT TO 对大表会锁表(尤其在 MySQL 5.7 及以前),线上务必选低峰期操作
– 如果表里有全文索引,CONVERT TO 会失败,得先删索引、改完再重建
客户端连接也要同步配 utf8mb4
就算库和表都改好了,如果应用连上去时没声明字符集,照样存乱码。关键不在服务端配置,而在连接初始化阶段:
- PHP PDO 要加
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4" - Java JDBC URL 加参数:
?characterEncoding=utf8mb4&useUnicode=true - Node.js mysql2 配置项写
charset: 'utf8mb4' - 命令行客户端启动时加
--default-character-set=utf8mb4,否则mysql -u root -p默认用utf8
验证是否生效:连上后执行 SELECT @@character_set_client, @@character_set_connection, @@character_set_results;,三个值都应为 utf8mb4。只要有一个不是,客户端发过来的字节就被截断或误判了。
为什么不能跳过排序规则(collation)直接设 utf8mb4
字符集(character set)管“能存哪些字符”,排序规则(collation)管“怎么比较和排序”。比如 utf8mb4_unicode_ci 和 utf8mb4_0900_as_cs 对大小写、重音符号的处理完全不同。
- 老项目迁移到 utf8mb4,优先用
utf8mb4_unicode_ci(兼容性好,MySQL 5.7+ 支持) - 新项目建议用
utf8mb4_0900_as_cs(区分大小写 + 重音敏感,更符合现代语义) - 千万别混用:同一个库下不同表用不同 collation,
JOIN时可能报Illegal mix of collations - 修改 collation 不改变已存数据的字节,但会影响
ORDER BY、GROUP BY、索引查找行为
真正麻烦的是历史数据里已经混了 latin1 编码的“假 utf8”内容——这种没法靠 CONVERT TO 自动修复,得人工识别、导出再转码。所以改之前,一定先备份,再小范围试改一张表,用真实业务数据跑一遍读写逻辑。


















