mysql容器必须显式配置utf8mb4字符集和+08:00时区,通过环境变量mysql_character_set_server=utf8mb4、mysql_collation_server=utf8mb4_unicode_ci、mysql_time_zone=+08:00及tz=asia/shanghai双重设置,并验证character_set_server、time_zone及now()与utc_timestamp()差值。

MySQL容器默认用 latin1 字符集、SYSTEM 时区,直接跑业务会出乱码或时间错位——必须显式配置。
启动时通过环境变量设置字符集
最稳妥的方式是在 docker run 或 docker-compose.yml 中用环境变量覆盖默认值。MySQL官方镜像支持 MYSQl_CHARACTER_SET_SERVER 和 MYSQl_COLLATION_SERVER:
-
MYSQl_CHARACTER_SET_SERVER=utf8mb4(不是utf8,后者只支持 BMP 字符) -
MYSQl_COLLATION_SERVER=utf8mb4_unicode_ci(推荐,比_bin更利于排序比较) - 这两个变量仅影响服务器级默认值,不会改已存在的数据库/表字符集
同时指定时区避免时间函数偏差
MySQL 容器默认用宿主机时区,但 Docker 启动时若没挂载或传参,NOW()、CURDATE() 可能返回 UTC 时间,和应用层不一致:
- 加环境变量
TZ=Asia/Shanghai(注意是系统时区名,不是 MySQL 的+08:00) - 再配
MYSQL_TIME_ZONE=+08:00—— 这个才是 MySQL 内部生效的时区参数 - 二者要一起设:只设
TZ不影响 MySQL server 的time_zone系统变量;只设MYSQL_TIME_ZONE但容器内无对应 tzdata,可能报错Unknown or incorrect time zone: 'Etc/UTC'
验证配置是否真正生效
进容器执行 mysql -u root -p 后,别只看 SHOW VARIABLES LIKE 'character_set%',关键要看这三处:
-
SHOW VARIABLES LIKE 'character_set_server';→ 应为utf8mb4 -
SHOW VARIABLES LIKE 'time_zone';→ 应为+08:00(不是SYSTEM) -
SELECT NOW(), UTC_TIMESTAMP();→ 两者应相差 8 小时 - 如果
character_set_client还是latin1,说明客户端连接没带?charset=utf8mb4,得在连接串里补上
最容易被忽略的是:容器重启后,character_set_database 仍沿用旧库的字符集,新创建的库才继承 server 设置;时区一旦设错,CONVERT_TZ() 会静默失败。动手前先确认镜像版本——MySQL 5.7 和 8.0 对 MYSQL_TIME_ZONE 的兼容性略有差异。











