最可靠方式是用 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 启动参数,置于镜像名之后、其他选项之前;官方镜像不识别 mysql_charset 环境变量,必须通过 mysqld 服务端参数配置,且需验证运行时变量确认生效。

直接用 --character-set-server 启动参数最可靠
MySQL 官方镜像(5.7 / 8.0+)支持在 docker run 时通过服务端启动参数强制覆盖默认字符集。这是最轻量、无需挂载文件、也不依赖环境变量的方案,适用于快速验证或 CI/CD 场景。
关键点在于:必须把字符集参数放在镜像名 之后、容器命令之前,否则会被忽略。官方文档明确说明这些是 mysqld 的 server option,不是容器运行时参数。
-
docker run命令中,--character-set-server=utf8mb4和--collation-server=utf8mb4_unicode_ci必须写在mysql:8.0这类镜像标签之后、任何-e或--name之前 - 不要写成
-e MYSQL_CHARSET=utf8mb4—— 这个环境变量只被部分第三方镜像识别,官方镜像不处理它 - 如果同时指定
--init-file或挂载/docker-entrypoint-initdb.d/脚本,这些脚本里建库建表时会自动继承character_set_server,无需再显式加CHARACTER SET utf8mb4
示例命令:
docker run -d \ --name mysql-utf8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=root \ mysql:8.0 \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci
为什么不能只靠环境变量 MYSQL_CHARSET
官方 MySQL Docker 镜像(mysql:5.7、mysql:8.0 等)的 entrypoint 脚本 不读取 MYSQL_CHARSET 或 MYSQL_COLLATION 环境变量。它们只用于初始化数据库(MYSQL_DATABASE)、设置 root 密码等基础动作,字符集配置完全交给 mysqld 自身处理。
你看到某些博客写了 -e MYSQL_CHARSET=utf8mb4,大概率是用了非官方镜像(如 bitnami/mysql),或者混淆了 MariaDB 镜像的行为。在官方镜像里设这个变量,SHOW VARIABLES LIKE 'character_set_server' 仍会返回 latin1。
- 执行
docker logs mysql-utf8,能看到启动日志里有类似mysqld: Character set 'utf8mb4' loaded才算真正生效 - 如果只设环境变量没加启动参数,连日志里都不会出现 utf8mb4 相关提示
- MySQL 8.0.31+ 开始,
utf8mb4已是编译默认值,但 Docker 镜像为了兼容旧行为,仍会在未显式指定时 fallback 到latin1
docker-compose.yml 里怎么写才不踩坑
在 docker-compose.yml 中,启动参数要放进 command 字段,且必须用数组格式(不能写成字符串),否则 YAML 解析会出错或参数被截断。
- 错误写法:
command: --character-set-server=utf8mb4(单字符串 → 参数被当做一个整体传给 shell,mysqld收不到) - 正确写法:用 YAML 数组,每个参数单独一项,确保空格和等号不被破坏
-
command会覆盖镜像默认的ENTRYPOINT,所以必须包含完整的mysqld启动逻辑,不能只写参数
正确示例:
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
command: [
"--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci"
]
ports:
- "3306:3306"
注意:如果你还挂载了自定义 my.cnf,command 参数优先级高于配置文件,两者冲突时以 command 为准。
验证是否真的生效了
别只信配置,一定要进容器查运行时变量。很多用户改完配置就以为好了,结果应用连上去还是问号——因为连接层(character_set_client、character_set_results)没对齐。
- 先连进 MySQL:
docker exec -it mysql-utf8 mysql -uroot -proot - 执行:
SHOW VARIABLES LIKE 'character\_set\_server';→ 必须返回utf8mb4 - 再执行:
SHOW VARIABLES LIKE 'collation\_server';→ 必须返回utf8mb4_unicode_ci - 额外检查:
SHOW VARIABLES LIKE 'character\_set%';,重点关注character_set_client和character_set_results,它们默认也随 server 变,但如果客户端连接时指定了charset=latin1,照样乱码
真正容易被忽略的是:即使服务端设对了,应用代码里 JDBC URL 没加 ?characterEncoding=utf8mb4,或者 Python 的 pymysql.connect() 没传 charset='utf8mb4',乱码照旧。字符集链路从来不是单点问题。











