mysql 5.7 初始化时必须显式配置 collation-server = utf8mb4_bin,仅设 character-set-server = utf8mb4 不足;因默认 fallback 为 utf8mb4_general_ci,且初始化(--initialize)不读 my.cnf,需启动后手动修正库表 collation 并确保各层级(server/database/table/column/connection)统一。

MySQL 5.7 初始化时必须显式指定 collation-server,不能只靠 character-set-server
只设 character-set-server = utf8mb4 不够——5.7 默认会 fallback 到 utf8mb4_general_ci,哪怕你没写 collation-server。要强制初始化用 utf8mb4_bin,必须在 [mysqld] 段里明确写死:collation-server = utf8mb4_bin。
常见错误现象:建库后执行 SHOW VARIABLES LIKE 'collation_server'; 返回 utf8mb4_general_ci,但配置文件里明明写了 utf8mb4_bin;这是因为配置未加载、或被其他配置覆盖(比如 my.cnf 被拆成多个文件,[mysqld] 段落在后面被重写)。
- 确认配置生效:重启后执行
SHOW VARIABLES LIKE 'collation_server';,输出必须是utf8mb4_bin - 检查是否多配置文件干扰:运行
mysqld --verbose --help | grep "Default options",看实际读取路径,避免/etc/my.cnf和/usr/my.cnf冲突 -
init_connect ='SET NAMES utf8mb4'对utf8mb4_bin无效——它只设置连接层字符集,不改排序规则;客户端仍需自己执行SET COLLATION_CONNECTION = utf8mb4_bin才能保证比较行为一致
新建数据库时仍需重复声明 COLLATE utf8mb4_bin,服务端默认值不兜底
即使 collation-server 已设为 utf8mb4_bin,执行 CREATE DATABASE db1; 后查 SHOW CREATE DATABASE db1;,你会发现 collation 还是 utf8mb4_general_ci。这是 5.7 的坑:它只在“无任何显式指定”时才用 server 级 collation,但建库语句隐式触发了旧逻辑。
- 安全写法永远是显式声明:
CREATE DATABASE db1 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; - 如果漏了,后续建表时字段级 collation 会继承库级值,而库级值不是你想要的
utf8mb4_bin,导致WHERE name = 'A'匹配到'a' - 已有库无法靠
ALTER DATABASE ... COLLATE改变已存在表的字段 collation,只能逐表ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
utf8mb4_bin 对索引和查询的影响容易被低估
utf8mb4_bin 是二进制排序,大小写敏感、重音敏感,这直接改变索引匹配逻辑和查询计划。例如 name VARCHAR(100) 字段加了普通索引,用 WHERE name = 'ABC' 能走索引,但用 WHERE UPPER(name) = 'ABC' 就不能——因为函数破坏了索引前缀。
- 区分大小写的业务场景(如 token、密码哈希、唯一标识符),
utf8mb4_bin是刚需,但要注意应用层所有比较逻辑必须对齐 - 如果字段上已有索引,改 collation 后 MySQL 会重建索引,但不会自动调整索引定义;建议改完后执行
ANALYZE TABLE table_name;更新统计信息 - 连接层 collation(
collation_connection)若仍是utf8mb4_general_ci,会导致ORDER BY结果与预期不符——排序按连接层规则,而非字段或表级规则
Docker 或脚本化初始化时,mysqld --initialize 不读 my.cnf
用 mysqld --initialize --datadir=/var/lib/mysql 初始化数据目录时,my.cnf 中的 collation-server 完全不生效。初始化过程绕过配置文件,硬编码用 5.7 默认值(latin1_swedish_ci 或 utf8mb4_general_ci)。
- 正确做法:先初始化,再启动 mysqld 前确保
my.cnf已就位且collation-server = utf8mb4_bin已写入,然后首次启动时执行ALTER DATABASE mysql COLLATE = utf8mb4_bin;(谨慎操作) - 更稳妥方案:初始化后立即运行 SQL 脚本批量修正:
ALTER DATABASE db_name CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;+ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; - Docker 用户注意:
my.cnf必须挂载到容器内标准路径(如/etc/mysql/my.cnf),且权限为644,否则 mysqld 静默跳过
COLLATE,或者应用连上来没发 SET NAMES utf8mb4 COLLATE utf8mb4_bin,行为就悄悄变了。











