必须挂载到 /etc/mysql/conf.d/ 而非 /etc/mysql/my.cnf,因官方镜像按 /etc/mysql/my.cnf → /etc/mysql/conf.d/*.cnf → /etc/mysql/mysql.conf.d/*.cnf 顺序加载,conf.d 目录专为用户自定义设计,支持叠加覆盖、权限友好且不破坏内置安全初始化逻辑。

挂载 my.cnf 到 /etc/mysql/conf.d/ 而不是 /etc/mysql/my.cnf
直接覆盖 /etc/mysql/my.cnf 会导致容器启动失败或丢失 socket、pid-file 等关键路径配置,因为 MySQL 官方镜像(如 mysql:8.0)在初始化时依赖该文件里的基础声明。真正的用户定制入口是 /etc/mysql/conf.d/ 目录——它被设计为只叠加、不破坏,且按字母序加载所有 *.cnf 文件,后加载的同名参数会覆盖先加载的。
常见错误现象包括:容器反复重启、日志里报 Can't start server: Bind on unix socket: Permission denied 或 Unknown variable 'character-set-server'(说明配置未生效或被忽略)。
- 必须确保宿主机上的配置文件以
.cnf结尾,例如my-custom.cnf,不能叫my.cnf放进/etc/mysql/conf.d/——虽然能用,但易与主配置混淆 - 文件权限需为 644,且容器内
mysql用户要有读取权;若用:ro挂载,可避免意外写入 - 想控制加载顺序?给文件加数字前缀,比如
01-charset.cnf、02-performance.cnf
配置文件里只写 [mysqld] 段,别碰 [client] 或其他段
MySQL Docker 镜像的启动逻辑只关心 [mysqld] 下的参数;[client]、[mysql] 等段在容器内几乎不被读取,写了也无效,还可能干扰调试。尤其注意:不要在自定义配置里写 !includedir 或 !include,镜像本身不支持运行时 include,会导致解析失败。
典型有效写法:
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci max_connections = 500 innodb_buffer_pool_size = 1G slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log
-
bind-address默认是127.0.0.1,如需远程访问,改成0.0.0.0或直接注释掉该行 -
skip-host-cache和skip-name-resolve建议加上,避免 DNS 解析延迟导致连接超时 - 日志路径必须指向容器内已挂载的目录(如
/var/log/mysql),否则启动报错Failed to open log file
docker run 中 -v 挂载路径必须精确到文件级
挂载整个目录(如 -v ./conf:/etc/mysql/conf.d)看似方便,但容易因宿主机目录下存在隐藏文件(如 .DS_Store、~$config.cnf)导致 MySQL 启动失败——它会尝试加载所有 *.cnf,哪怕文件内容为空或语法错误。
更稳妥的做法是单文件挂载:
docker run -d \ --name mysql-prod \ -e MYSQL_ROOT_PASSWORD=secr3t \ -v $(pwd)/my-custom.cnf:/etc/mysql/conf.d/my-custom.cnf:ro \ -v mysql-data:/var/lib/mysql \ -v $(pwd)/logs:/var/log/mysql \ -p 3306:3306 \ mysql:8.0
- 宿主机路径用
$(pwd)或绝对路径,避免相对路径在不同 shell 下解析异常 - 挂载日志目录时,确保宿主机对应路径已创建且权限可写(
chown -R 999:999 logs/,因为 MySQL 容器默认以 UID 999 运行) - 如果用
docker-compose.yml,volumes:下也要写成./my-custom.cnf:/etc/mysql/conf.d/my-custom.cnf:ro,不能写成目录映射
环境变量和 my.cnf 冲突时,谁优先?
环境变量(如 MYSQL_DATABASE)只在容器首次初始化时起作用,且仅触发建库、建用户等一次性操作;而 my.cnf 里的参数(如 max_connections)在每次 mysqld 启动时加载,优先级更高、更底层。但注意:某些参数无法被环境变量设置(如字符集、缓冲池大小),必须靠配置文件。
真正容易踩坑的是字符集相关项:
-
MYSQL_CHARSET=utf8mb4这类环境变量实际无效,镜像根本不识别——必须在[mysqld]里写character-set-server和collation-server - 如果
my.cnf里没设字符集,即使环境变量写了也没用;反过来,环境变量设了MYSQL_DATABASE,但my.cnf里设了init_connect='SET NAMES utf8mb4',后者会在每个新连接里执行,但不影响数据库/表默认字符集 -
default_authentication_plugin=mysql_native_password必须写在配置文件里,否则新版 MySQL 8.0+ 的客户端(尤其是旧版 PHP PDO)连不上
配置生效与否,最直接的验证方式是进容器执行:docker exec -it mysql-prod mysql -uroot -p -e "SHOW VARIABLES LIKE 'character_set%';",而不是只看容器是否起来。











