必须显式挂载volume才能持久化mysql数据;推荐用命名卷(如-v mysql-data:/var/lib/mysql),docker自动管理路径与权限,删除容器后数据仍保留,仅执行docker volume rm才彻底清除。

docker run 启动 MySQL 容器时,不加任何挂载参数,容器一删,/var/lib/mysql 里的所有数据就彻底消失——这不是“重启失效”,是物理删除。必须显式挂载,才能保住数据库。
用 docker volume 挂载命名卷(推荐生产环境)
Docker 自己管理存储位置和权限,不用操心宿主机路径、SELinux 或用户 UID 冲突,适合绝大多数场景。
- 创建并使用命名卷只需一条命令:
docker run -d --name mysql-prod -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 -p 3306:3306 mysql:8.0 - 卷名
mysql-data是逻辑标识,Docker 自动在/var/lib/docker/volumes/下分配真实路径 - 删除容器后,运行
docker volume ls仍能看到该卷;只有执行docker volume rm mysql-data才真正清空数据 - 若需备份,直接
tar -cf mysql-data-backup.tar -C $(docker volume inspect mysql-data -f '{{.Mountpoint}}') .
用 -v /host/path:/var/lib/mysql 绑定挂载(适合开发或需直访文件)
把宿主机某个目录(如 /opt/mysql/data)硬映射进容器,路径完全可控,但责任也全在你手上。
- 必须提前创建目录并设对权限:
mkdir -p /opt/mysql/data && chown -R 999:999 /opt/mysql/data(MySQL 官方镜像默认以 UID 999 运行) - 若宿主机是 SELinux 系统,得加
:z或:Z标签:-v /opt/mysql/data:/var/lib/mysql:z - 不要挂载空目录到已有数据的容器:MySQL 启动时发现
/var/lib/mysql非空但无ibdata1,会拒绝启动并报错mysqld: Can't read dir of '/var/lib/mysql/' (Errcode: 13 - Permission denied) - 日志、配置可一并挂载:
-v /opt/mysql/conf/my.cnf:/etc/mysql/my.cnf:ro,注意加:ro只读防止容器篡改
docker-compose.yml 中声明卷更可靠
手动敲 docker run 容易漏参数,docker-compose 能固化挂载逻辑,避免重复出错。
- 正确写法示例:
services: mysql: image: mysql:8.0 volumes: - mysql-data:/var/lib/mysql - ./conf/my.cnf:/etc/mysql/my.cnf:ro environment: MYSQL_ROOT_PASSWORD: "123" volumes: mysql-data: - 注意
volumes:顶层块必须声明mysql-data:,否则 Docker Compose 会当作绑定挂载处理,导致创建匿名卷 - 若想指定命名卷驱动或选项(如用
local驱动配o=bind),需在volumes块里展开定义,不能只写名字
初始化后别动挂载点,尤其别混用两种方式
MySQL 数据目录结构敏感,挂载方式一旦确定就不能中途切换。- 已用命名卷运行过容器,再改成绑定挂载,会导致容器内看到的是空目录或旧残留,MySQL 拒绝启动
- 容器首次启动时,MySQL 会自动初始化数据目录(生成
mysql、sys系统库等);这个过程依赖挂载点为空或含合法初始化数据 - 如果你从物理机迁移数据进来,务必确保文件属主是
999:999,且禁用 AppArmor/SELinux 干预,否则日志里只会写Can't start server: Bind on TCP/IP port: Address already in use这类误导性错误
最常被忽略的一点:挂载成功不等于数据安全。命名卷虽由 Docker 管理,但它仍落在单台宿主机磁盘上——没做定期 mysqldump 或 WAL 归档,遇到磁盘故障一样全丢。持久化只是第一步,备份策略得跟上。











