alter database 必须同时指定 charset 和 collation,否则可能引入意外排序规则;该操作仅影响新建对象,已有表列需单独修改;客户端连接也需显式设置 utf8mb4 编码,否则导致乱码假象;升级 utf8mb3 到 utf8mb4 时需注意字段长度超限风险。

ALTER DATABASE 时 charset 和 collation 参数必须同时指定
只改 CHARSET 不指定 COLLATION,MySQL 会用该字符集的默认排序规则,但这个默认值可能不是你想要的(比如 utf8mb4 默认是 utf8mb4_0900_ai_ci,而旧库常用 utf8mb4_unicode_ci)。一旦排序规则不一致,后续 JOIN、ORDER BY 或索引行为可能出人意料。
实操建议:
- 先查当前库的字符集和排序规则:
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'your_db'; - 执行修改时显式写全:
ALTER DATABASE your_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; - 注意等号两边要有空格,MySQL 对语法敏感,
CHARACTER SET=utf8mb4会报错
表和列不会自动继承新数据库字符集
ALTER DATABASE 只影响后续新建的表和列,已有对象的字符集保持不变。这是最容易被忽略的一点——改完库以为万事大吉,结果 SHOW CREATE TABLE 一看,表还是 utf8,字段仍是 latin1_swedish_ci。
实操建议:
- 逐个修正表:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 如果只要改某几个字段,用
MODIFY COLUMN更精准,避免整表重建开销:ALTER TABLE tbl_name MODIFY COLUMN col_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 批量生成语句可查
INFORMATION_SCHEMA.COLUMNS,但务必先备份——CONVERT TO在大表上会锁表
客户端连接字符集不匹配会导致乱码假象
即使库、表、列全改成 utf8mb4,如果客户端连接时没声明编码,MySQL 仍按 latin1 解析请求,存进去的是乱码,读出来也是乱码。这不是数据损坏,而是“错进错出”造成的假性成功。
实操建议:
- 连接时显式指定:
mysql --default-character-set=utf8mb4 -u user -p db_name - 程序里设置连接参数,例如 Python 的
pymysql.connect(..., charset='utf8mb4'),PHP 的mysqli_set_charset($conn, 'utf8mb4') - 检查当前连接实际生效的变量:
SHOW VARIABLES LIKE 'character\_set%';关键看character_set_client、character_set_connection、character_set_results三个是否都是utf8mb4
从 utf8 升级到 utf8mb4 要小心 3 字节 vs 4 字节限制
utf8 在 MySQL 里其实是 utf8mb3,最多存 3 字节 UTF-8 字符;utf8mb4 才真正支持 4 字节(比如 emoji、某些生僻汉字)。直接 CONVERT TO 可能失败,因为原来定义的 VARCHAR(255) 在 utf8mb4 下实际占用字节数翻倍,可能超出 InnoDB 单行 65535 字节限制。
实操建议:
- 提前检查字段长度:对
VARCHAR字段,按最大 4 字节估算,VARCHAR(255)→ 最多占 1020 字节;若一行多个长字段,加起来超限就会报Row size too large - 必要时缩减长度,比如
VARCHAR(191)是常见安全值(191×4=764 - 确认
innodb_large_prefix是否启用(MySQL 5.7+ 默认 ON),否则前缀索引长度也受限制











