Docker 安装 MySQL 8:数据卷、字符集、远程访问一步到位

Docker 装 MySQL 最大的好处是版本干净、随起随删;最大的坑是默认没有持久化——容器一删数据就没。这篇按「能跑 → 不丢数据 → 好用」三步把 MySQL 8 容器配到生产可用的程度。

一、最短命令(只用来本地试试)

docker run -d --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:8.4

30 秒能连上,但容器删了数据就没了。正式用请往下看。

二、标准命令:带数据卷和配置

docker run -d \
  --name mysql8 \
  --restart unless-stopped \
  -p 3306:3306 \
  -v /data/mysql/data:/var/lib/mysql \
  -v /data/mysql/conf:/etc/mysql/conf.d \
  -e MYSQL_ROOT_PASSWORD='你的root密码' \
  -e TZ=Asia/Shanghai \
  mysql:8.4

逐个解释挂载:

  • /data/mysql/data:/var/lib/mysql —— 核心。数据落在宿主机,容器升级、重建都不丢。目录不存在 Docker 会自动建,但要确认属主能被容器内 mysql 用户(uid 999)写入。
  • /data/mysql/conf:/etc/mysql/conf.d —— 把自定义 my.cnf 放宿主机这个目录,容器自动加载。

自定义配置 /data/mysql/conf/my.cnf:

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
max_connections = 500
innodb_buffer_pool_size = 512M
slow_query_log = 1
long_query_time = 1

改完 docker restart mysql8 生效,docker exec mysql8 mysql -uroot -p -e "show variables like 'character%'" 验证。

三、建远程账号(别直接暴露 root)

docker exec -it mysql8 mysql -uroot -p
CREATE USER 'app'@'%' IDENTIFIED BY '强密码';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX ON `appdb`.* TO 'app'@'%';
FLUSH PRIVILEGES;

MySQL 8 默认认证插件是 caching_sha2_password,老客户端(PHP 5.x、旧版 Navicat)连不上报 2059 时,要么升级客户端,要么建号时指定 IDENTIFIED WITH mysql_native_password BY '...'。

四、compose 写法(推荐)

services:
  mysql:
    image: mysql:8.4
    container_name: mysql8
    restart: unless-stopped
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "你的root密码"
      TZ: Asia/Shanghai
    volumes:
      - ./data:/var/lib/mysql
      - ./conf:/etc/mysql/conf.d
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p你的root密码"]
      interval: 10s
      timeout: 5s
      retries: 5

healthcheck 配上之后,depends_on: { condition: service_healthy } 才有意义——否则应用容器比 MySQL 先起,连接失败。

五、常见问题

现象 原因 解法
容器反复重启,日志 Access denied for root 数据卷里已有旧数据,环境变量的密码只在首次初始化时生效 删掉数据卷目录重新初始化,或进容器手改密码
外部连不上,ERROR 2003 -p 3306:3306 没加 / 云安全组没放行 docker port mysql8 确认映射,再查安全组
中文变 ??? 服务端字符集不是 utf8mb4 挂载 conf 按第二节配置
磁盘被日志写满 binlog 或容器日志无限增长 my.cnf 加 binlog_expire_logs_seconds=604800;daemon.json 配 log-opts
时间差 8 小时 容器默认 UTC -e TZ=Asia/Shanghai

六、备份怎么办

数据卷不等于备份。每天一条 cron 最省事:

docker exec mysql8 sh -c 'exec mysqldump -uroot -p"密码" --all-databases' | \
  gzip > /data/backup/mysql-$(date +%F).sql.gz

配合 find /data/backup -mtime +7 -delete 保留最近 7 天。


相关工具:Docker 命令速查 · JSON 格式化 · Linux 命令速查

还有 65 个免费在线工具

纯前端实现,不用注册,数据不上传服务器。

浏览全部工具