☰
Docker与MySQL完美搭配:从镜像拉取到远程连接的全流程实战
2026/9/28 12:17:38 网站建设 项目流程

最近一段时间,我连续被好几个朋友问同一个问题:Docker 和 MySQL 到底怎么搭配?Docker Desktop 明明装好了,docker pull mysql也执行了,结果启动报错、远程连不上、进入容器不会执行 SQL,整个过程卡得死死的。这其实不是个别现象,Docker 跑 MySQL 跟直接在 Windows 或 Linux 上装 MySQL 是两套完全不同的玩法,很多人拿裸装的思路去套容器,自然处处碰壁。

这篇文章我想从零开始,把整套链路完整走一遍:Docker Desktop 的准备、MySQL 镜像拉取、正式容器的启动参数、进入容器执行 SQL 文件、远程客户端连接,以及常用的配置调优和排错。目标很直接,就是让你照着做能跑通,并且理解每一步为什么这样做,而不是死记命令。

1. Docker 跑 MySQL 前,先搞清这套玩法跟裸装到底差在哪

1.1 容器里那个 MySQL 不是"在 Windows 上装的 MySQL"

很多人第一次用 Docker 装 MySQL,脑子里还停留在"下载安装包,下一步下一步,然后连 3306 端口"的惯性里。实际上,Docker 里的 MySQL 是一个一次性可替换的运行环境。你docker run创建容器,本质上是基于镜像启动了一个隔离的进程,这个进程里运行着 Linux 版的 mysqld,它的文件系统、配置文件、数据目录都是独立的一套,跟你宿主机上的 Windows 或者 macOS 没有直接关系。

这就引出了几个关键差异:

  • 数据目录:容器内的/var/lib/mysql是 MySQL 存放数据的地方,但容器一旦被删除,里面的数据默认也会跟着消失。所以必须把宿主机目录或数据卷挂载进去,数据才安全。
  • 配置文件:裸装 MySQL 读的是my.ini或my.cnf,容器内也有这个文件,但你需要通过挂载方式覆盖它,或者用环境变量控制一部分参数。
  • 端口:容器内 MySQL 默认监听 3306,但这个端口默认不直接暴露给宿主机。你得通过-p 3306:3306做端口映射,宿主机才能访问。
  • 进程生命周期:容器不是后台常驻的"服务",它更像一个被docker start/stop控制的独立进程单元。docker restart mysql8不会像 Windows 服务管理器那样弹出一堆权限提示。

我见过一个典型误区:有人在容器里执行了service mysql start,然后问我"为什么还是连不上"。因为容器启动时真正执行的命令是mysqld,也就是启动脚本里那个入口点(entrypoint)。容器生命周期绑定的是这个 mysqld 进程,而不是 systemd 或者 service 体系。你在容器里手动service mysql start通常毫无意义,甚至会出现"进程已经跑着,但容器认为主进程死了"的错乱现象。

1.2 什么场景适合 Docker 版 MySQL,什么场景别硬上

Docker 版 MySQL 最大的价值是环境隔离和快速重建。比如你同时维护多个项目的数据库,项目 A 用 MySQL 5.7,项目 B 用 MySQL 8.0,裸装就得处理版本冲突;用 Docker 就很简单,两个容器各跑各的版本,端口分别映射到 3306 和 3307。再比如你写完一个项目的部署文档,新同事要复现环境,给一条docker run命令就够了,不用在对方机器上安装、初始化、改配置反复折腾。

还有一类高频场景是本地开发。我经常在本地起一个临时 MySQL 容器,用来验证某条 SQL 的执行计划、测试慢查询优化效果,或者跑自动化测试的数据库初始化脚本。测试完直接docker rm -f,干净利落,不影响本机已有的数据库。

但有些场景我不建议硬上 Docker。如果你要跑一个在线高并发生产库,并且团队对容器编排、网络、存储性能没有足够经验,裸装或云数据库往往是更稳的选择。Docker 部署 MySQL 在生产环境不是不行,但需要额外处理数据卷性能、备份恢复策略、容器 CPU 内存限制等一堆问题,很多团队折腾半天,最后发现还不如买一个云数据库省心。另外,如果你在低配 Windows 上跑 Docker Desktop,本身就要吃不少内存,再跑一个 MySQL 容器,电脑可能会明显变卡。这一点事先要有预期。

2. Docker Desktop 和镜像准备:装好不等于能用

2.1 Windows 下装 Docker Desktop 的两个后端与一个常见报错

Windows 上装 Docker Desktop,最关键的决策是后端选 WSL 2 还是 Hyper-V。WSL 2 是目前的主流推荐,启动快、内存管理更聪明、跟 Windows 文件系统交互也方便。如果你用的是 Windows 10/11 专业版、企业版或教育版,也可以选 Hyper-V;但如果你是 Windows Home,没得选,老老实实用 WSL 2。

安装过程本身不复杂,去 Docker 官网下载 Docker Desktop Installer,双击安装,安装器会让你选是否使用 WSL 2。这里有个容易忽略的点:如果之前没装过 WSL 内核,最好先打开 PowerShell 执行wsl --install,然后重启电脑再装 Docker Desktop。否则 Docker Desktop 启动时会提示找不到 WSL 内核,或者报WSL kernel version too low。

很多人卡在启动这一步:打开 Docker Desktop,右下角那个鲸鱼图标转半天,然后弹出一个类似Virtualization support not detected或者Docker Desktop failed to start because...的报错。这个问题十有八九是 BIOS 里的虚拟化开关没开。解决方法:重启电脑进 BIOS,找到Intel Virtualization Technology(Intel 平台)或SVM Mode(AMD 平台),设为 Enabled,保存退出再启动。装完之后在 PowerShell 里执行下面命令验证:

wsl --status wsl --set-default-version 2 docker version

docker version能正常打印 Client 和 Server 两段信息,才说明 Docker 引擎真的跑起来了。注意,如果只显示了 Client 段,Server 段报错,通常就是 Docker Desktop 里的引擎没启动。先把 WSL 2 后端跑通,再继续下一步。

还有一个容易被忽略的点:Docker Desktop 默认会占 2GB 左右内存,在Settings -> Resources里可以调 WSL 2 的内存上限。我个人习惯给 Docker 分配 4GB 左右,因为后面还要跑 MySQL 和可能的数据集,太抠会卡。

2.2 拉取 MySQL 镜像:版本选择有讲究

镜像版本这块,我不建议直接写latest。latest标签虽然方便,但 MySQL 大版本升级时行为变化很大,尤其是认证插件、字符集默认值这些,很可能让你昨天还能连的客户端今天突然连不上。更稳妥的做法是固定大版本,比如:

docker pull mysql:8.0

这样拉取的是 8.0 系列的最新补丁版,不会突然跳到 9.x。如果你需要完全锁定,也可以指定具体小版本,比如mysql:8.0.36。对于老项目兼容需求,可能还要用mysql:5.7,但要注意 5.7 已经停止官方更新,新项目不建议再选。

mysql:8.0镜像默认的认证插件是caching_sha2_password,这跟 MySQL 5.7 时代的mysql_native_password不一样。某些老版本的 Navicat、SQLyog、JDBC 驱动在连接时会出现Authentication plugin 'caching_sha2_password' cannot be loaded或类似报错。这通常不是配置问题,而是客户端太旧不认识新认证协议。遇到这种情况,要么升级客户端驱动,要么在创建用户时显式指定mysql_native_password,后面授权部分我会详细讲。

2.3 用临时容器验证镜像是否正常

镜像拉下来之后,先别急着配一堆参数,我习惯先跑一个临时容器验证镜像能不能正常初始化。这个步骤能帮你区分"镜像问题"和"配置问题":

docker run --name mysql-test \ -e MYSQL_ROOT_PASSWORD=Root@123 \ -d mysql:8.0

执行完等十几秒,然后看日志:

docker logs mysql-test

如果看到类似ready for connections或者mysqld: ready for connections的日志,说明镜像本身没问题。MySQL 官方镜像首次初始化会做几件事:创建数据目录、初始化系统表、设置 root 密码。这些步骤执行完需要一个过程,在这个过程中如果你急着连接,会报Access denied或连接拒绝。看到日志里出现ready for connections才算真正初始化完成。

验证完这个临时容器,直接删掉:

docker rm -f mysql-test

这里已经能看出容器的一个特性:没有挂载数据卷时,删除容器等于连数据一起删。刚才只是在测试,数据无所谓,真正使用时必须挂载。

3. 正式启动:一条 docker run 把目录挂载、密码、端口一次配齐

3.1 推荐的生产型启动命令逐参数拆解

临时容器验证通过后,就可以正式创建 MySQL 容器了。下面这条命令是我在本地开发和轻量测试环境里最常用的模板:

docker run -d \ --name mysql8 \ --restart unless-stopped \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=Root@123 \ -e TZ=Asia/Shanghai \ -v /d/docker/mysql/data:/var/lib/mysql \ -v /d/docker/mysql/config/my.cnf:/etc/mysql/conf.d/my.cnf \ mysql:8.0

逐个拆解一下:

  • -d:后台运行容器,不加的话终端会被 mysqld 日志占住,一关终端容器就停。
  • --name mysql8:给容器起个固定名称,之后docker exec、docker start、docker logs都靠这个名称引用。不命名的话容器会随机生成一个很别扭的名字。
  • --restart unless-stopped:容器异常退出时自动重启,但如果你手动docker stop它,就不会自动拉起来。这个策略对本地开发很友好,重启 Docker Desktop 后 MySQL 会自动恢复。
  • -p 3306:3306:宿主机 3306 端口映射到容器 3306 端口。左侧是宿主机端口,右侧是容器端口,改左侧就能换对外端口。
  • -e MYSQL_ROOT_PASSWORD=Root@123:设置 root 密码。官方镜像首次初始化时会读取这个环境变量。注意,这个密码只在首次初始化数据目录时生效。数据目录已经初始化之后,你再改这个环境变量重启容器,密码不会跟着变。
  • -e TZ=Asia/Shanghai:不设置时区,MySQL 的CURRENT_TIMESTAMP可能跟你本地时间差 8 小时。
  • -v /d/docker/mysql/data:/var/lib/mysql:把宿主机目录挂到容器数据目录,这是数据持久化的关键。
  • -v /d/docker/mysql/config/my.cnf:/etc/mysql/conf.d/my.cnf:把自定义配置文件挂进容器的配置目录。/etc/mysql/conf.d/下所有.cnf文件都会被 mysqld 自动读取。

启动后执行docker ps看状态,如果容器一直在restarting,先别慌,用docker logs mysql8看日志。最常见的失败原因就是 data 目录挂载后权限不对,或者 my.cnf 里写了 MySQL 8.0 不认识或者不允许动态修改的参数。

3.2 目录挂载和数据卷到底怎么选

数据持久化有两种方式:bind mount(绑定挂载)和 named volume(命名卷)。

  • bind mount:直接指定/宿主机路径:/容器路径。路径直观,方便你把数据目录拷走备份,也能直接用编辑器改配置文件。缺点是 Windows 下路径写法要注意,/d/docker/mysql/data这种是 Git Bash 里的写法,PowerShell 下写D:\docker\mysql\data:/var/lib/mysql会有坑,需要写成/d/docker或D:/docker/mysql/data,建议统一用正斜杠加绝对路径。
  • named volume:写法是-v mysql_data:/var/lib/mysql,Docker 会自动在它管理的目录下创建卷,好处是不用关心具体路径,docker volume inspect mysql_data可以查看真实位置。缺点是你不太方便直接打开目录手动拷贝文件。

我个人在本地开发中用 bind mount 偏多,因为出了问题能直接进目录翻数据文件,还能顺带备份。如果你用 Docker Compose 管理多容器,用 named volume 更整洁。但无论哪种,必须保证宿主机目录有可写权限。Windows 下相对宽松,Linux 上经常遇到mysqld: Can't create/write to file '/var/lib/mysql/'这类权限错误,排查思路就是看目录属主是不是 uid 999(MySQL 官方镜像内的 mysql 用户 uid),不行就chown -R 999:999或改用命名卷自动处理权限。

3.3 端口映射冲突怎么办

-p 3306:3306最常遇到的问题就是宿主机 3306 端口已经被占用。比如你电脑上本来装了 MySQL 服务,监听 3306,Docker 再映射就会报port is already allocated。

排查方法:

netstat -ano | findstr :3306

看到 PID 后,去任务管理器找到对应进程。如果是本机 MySQL 服务,可以把它停掉或者改成另一个端口;如果不想动本机 MySQL,Docker 这边就改端口映射:

docker run -d \ --name mysql8 \ -p 3307:3306 \ ...

这样宿主机 3307 映射到容器 3306,客户端连接时用localhost:3307即可。这里有个常见误会:有人以为改了容器内 MySQL 的端口,实际上你只需要改左侧映射,容器内还是 3306,不需要进容器改port=3307。

如果你把-p 3307:3306中的右侧也改成 3307,那反而更麻烦:容器内部 mysqld 默认监听 3306,如果配置没改,端口映射目标不存在,就连不上了。新手很容易在这一步绕晕,记住一句:左侧是宿主机要用的端口,右侧是容器内 MySQL 实际监听的端口,右侧别乱动。

4. 进入容器执行 SQL:docker exec 的一百种打开方式

4.1 交互式进入容器操作 MySQL

正式容器的核心操作之一就是进容器执行 SQL。很多人连不上网络客户端,第一反应是"镜像坏了",其实先进容器用命令行验证最直接。

最常规的交互方式:

docker exec -it mysql8 bash

进入容器 shell 后,再执行 mysql 客户端:

mysql -uroot -p

输入密码后进入 MySQL 交互界面,这时可以执行任意 SQL:

SELECT VERSION(); SHOW DATABASES; USE mysql; SELECT user, host FROM user;

可以一箭双雕,直接用镜像里的 mysql 客户端进入:

docker exec -it mysql8 mysql -uroot -p

它会提示输入密码。如果你想避免交互,或者要在脚本里自动执行,可以写成:

docker exec -it mysql8 mysql -uroot -p'Root@123' -e "SELECT NOW();"

但我个人不建议在命令行直接暴露密码,-p后面留空会让客户端交互提示输入,更安全。

如果你只想快速验证,可以用:

docker exec mysql8 mysql -uroot -p'Root@123' -e "SELECT 1;"

注意,不用-it也可以执行一次性命令。区别在于-t会分配伪终端,输出格式化更漂亮;不带-t适合做管道重定向。比如把 SQL 文件灌进 MySQL,就用不带-t的模式更合适。

4.2 不进入容器直接执行 SQL 文件

实际开发里更多场景是"本地有个 test.sql,要把它导入容器里的 MySQL"。你不需要先进容器再想办法把文件传进去,直接用标准输入重定向就行:

docker exec -i mysql8 mysql -uroot -p'Root@123' < test.sql

注意这里是-i而不是-it。-i保持标准输入打开,-t分配伪终端;重定向场景下不该有伪终端,处理\r\n和中文编码时更容易出问题。

同理,备份也是反过来的:

docker exec mysql8 mysqldump -uroot -p'Root@123' --databases mydb > mydb_backup.sql

这样备份文件直接落在宿主机当前目录,非常方便。我再强调一下:mysqldump 和 mysql 都是容器内部的命令,你通过docker exec调用,不用在宿主机安装任何 MySQL 客户端。

还有一种批量初始化的玩法:官方镜像支持把.sql、.sh文件放到挂载到/docker-entrypoint-initdb.d/的目录里,首次初始化数据目录时会自动执行。这对搭建开发环境特别有用,比如:

docker run -d \ --name mysql8 \ -e MYSQL_ROOT_PASSWORD=Root@123 \ -v /d/docker/mysql/data:/var/lib/mysql \ -v /d/docker/mysql/initdb:/docker-entrypoint-initdb.d \ mysql:8.0

initdb目录下的schema.sql会在 MySQL 首次启动时自动导入。这个机制很省事,但只对首次初始化生效,如果数据目录已经存在,再添加脚本不会重新执行。

4.3 容器内跑备份恢复

备份和恢复是日常绕不开的操作,容器场景下我推荐下面这套闭环:

备份到宿主机:

docker exec mysql8 mysqldump -uroot -p'Root@123' --single-transaction --routines --triggers mydb > /d/backup/mydb_$(date +%Y%m%d).sql

恢复时直接灌:

docker exec -i mysql8 mysql -uroot -p'Root@123' mydb < /d/backup/mydb_20260601.sql

恢复之前要先确保目标数据库存在,可以先用-e "CREATE DATABASE IF NOT EXISTS mydb"创建,或者导入--databases mydb的整库备份。

--single-transaction参数很关键,对 InnoDB 表可以在不锁表的情况下做一致性备份。如果数据量大,还可以考虑备份到容器内再拷出来,但正常本地开发用上面的管道式写法完全够。

5. 给远程客户端开绿灯:账号授权、认证插件和 SSL 连接

5.1 为什么 root 远程连不上

容器跑起来了,命令行能查询,接下来很多人会兴冲冲打开 Navicat 或 MySQL Workbench 连数据库,结果连不上。要理解这个现象,得分两层:容器网络层和 MySQL 账号层。

网络层方面,容器做了端口映射,宿主机 3306 能连到容器 3306,所以从本地客户端连接时地址写localhost或127.0.0.1就行。如果改成localhost还报错,多半不是网络问题。

账号层才是重头戏。MySQL 8.0 默认只给 root 创建了root@localhost账号,也就是仅允许从本地 socket 或回环地址连接。当你从宿主机通过 TCP 访问容器里的 MySQL 时,客户端连接来自容器的网关地址,在 MySQL 看来这是一个"远程"来源,root@localhost是不匹配的,于是报ERROR 1045 (28000): Access denied for user 'root'@'...'。

有人说"那我改 root 的 host 为 % 不就行了?"可以,但我不推荐在生产或共享环境里开放 root 远程登录。正确做法是创建专用应用账号。

5.2 新建应用账号并授权

进入容器:

docker exec -it mysql8 mysql -uroot -p

然后创建账号并授权:

CREATE USER 'app'@'%' IDENTIFIED BY 'App@123456'; GRANT ALL PRIVILEGES ON mydb.* TO 'app'@'%'; FLUSH PRIVILEGES;

'%'表示允许任意主机连接。如果只想让某个内网网段连接,可以写'192.168.1.%'。权限粒度看需求,ALL PRIVILEGES在本地开发够用,生产环境建议按最小权限给。

这里又要提到认证插件。MySQL 8.0 默认caching_sha2_password,老客户端支持不好。如果连接时报错或提示认证插件无法加载,可以在建账号时指定老协议:

CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'App@123456'; GRANT ALL PRIVILEGES ON mydb.* TO 'app'@'%';

或者针对已有账号修改:

ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'App@123456';

但要注意,mysql_native_password在 MySQL 8.0 里已经标记为 deprecated,未来大版本可能移除,新项目尽量用新插件并升级客户端。JDBC 8.0.x 以上驱动默认支持caching_sha2_password,多数的现代客户端也没问题。

5.3 遇到 1045、2002、SSL 错误的排查思路

远程连接常见的报错无非这几种,我一个个说:

ERROR 1045 (28000): Access denied for user

认证失败。先确认账号是否存在、密码是否正确、授权的 host 是否覆盖你当前的来源 IP。SQL 里可以这样查:

SELECT user, host, plugin FROM mysql.user;

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'

这个报错有意思。它表示你用的 MySQL 客户端尝试通过 socket 文件连接,而不是 TCP。当你在容器里执行mysql -uroot -p,默认走 socket,如果 socket 路径不对,就会出现。从宿主机外部用 Navicat 连接时走 TCP,一般不会出这个问题。真正遇到这个报错时,用 TCP 方式指定端口即可,比如在容器里执行:

mysql -h127.0.0.1 -P3306 -uroot -p

SSL 连接错误

我遇到过几次 MySQL 客户端提示SSL connection error或者 JDBC 提示Establishing SSL connection without server's key verification is not recommended。前者是客户端要求 SSL 但 MySQL 配置不支持,后者是 JDBC 默认开启 SSL 校验导致。

解决办法根据场景来:

  • 用 MySQL Workbench 连接时,把SSL选项卡设为No或If Available。
  • JDBC 连接串里追加useSSL=false&allowPublicKeyRetrieval=true。allowPublicKeyRetrieval这个参数在caching_sha2_password插件下很关键,否则可能出现公钥检索失败。
  • 如果你确实需要 SSL 连接,那就要在容器里配置证书,这个属于进阶玩法,本地开发一般不必折腾。

这一步配好之后,Navicat、MySQL Workbench、DBeaver 这些工具都能正常连上容器里的 MySQL 了。

6. 配置调优与避坑:my.cnf、慢日志、资源限制

6.1 自定义 my.cnf 的正确姿势

Docker 里的 MySQL 同样支持自定义配置文件。官方镜像的默认配置比较保守,很多项目要调整字符集、连接数、SQL 模式等,就需要在宿主机写好my.cnf挂载进去。

前面启动命令里挂载的是/etc/mysql/conf.d/my.cnf,这个路径下追加一个配置文件即可。一个常见的本地常用配置长这样:

[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci max_connections=500 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION default-time-zone=+08:00 lower_case_table_names=1

有几个参数要特别提醒:

  • lower_case_table_names:MySQL 8.0 在 Linux 上默认值是 0,即表名区分大小写。如果你从 Windows 迁移过来,Windows 上默认不区分,需要在初始化数据目录之前就定好这个值。如果已经初始化再改,服务可能启动失败,报错日志会提示Table 'mysql.plugin' doesn't exist之类。这时候只能调整配置后重新初始化数据目录,或者干脆全小写表名写代码。
  • sql_mode:我见过有些老的业务 SQL 不带 group by 全字段,如果沿用 MySQL 5.7 的默认严格模式,8.0 可能更严格,需要按业务调整。
  • max_connections:连接数不是越大越好,每个连接都有内存开销,容器内存有限时设太高反而容易 OOM。

改完配置重启容器:

docker restart mysql8

然后进容器验证:

docker exec mysql8 mysql -uroot -p -e "SHOW VARIABLES LIKE 'max_connections';"

6.2 开启慢查询日志定位慢 SQL

容器里的 MySQL 定位慢 SQL,方式跟裸装大同小异。在自定义配置中加上:

slow_query_log=1 slow_query_log_file=/var/lib/mysql/slow.log long_query_time=1

long_query_time=1表示超过 1 秒的查询记录到慢日志。注意,慢查询日志文件写在数据目录里,数据目录挂载到了宿主机,所以宿主机上直接就能打开看。

在容器内也可以实时查:

docker exec mysql8 mysql -uroot -p -e "SHOW VARIABLES LIKE 'slow_query_log';"

真正分析时,我常用两种方式。一是直接打开 slow.log 看,二是用 MySQL 自带的mysqldumpslow汇总:

docker exec mysql8 mysqldumpslow -s c -t 10 /var/lib/mysql/slow.log

-s c按查询次数排序,-t 10取前十名,能快速找出最频繁的慢查询。

额外的调试利器是EXPLAIN。拿到慢 SQL 后,在容器里执行:

EXPLAIN SELECT * FROM orders WHERE user_id = 123;

看type和rows字段,如果出现全表扫描或者预估行数特别大,就要考虑加索引。这套排查链路在 Docker 容器里跟裸装完全一样,只是入口换成了docker exec。

6.3 容器资源限制与常见启动失败排查

容器不是免费的。MySQL 跑在容器里同样要吃 CPU 和内存。我见过太多人电脑卡到飞起,就是因为 MySQL 容器的内存完全没有限制。给 Docker 一个硬指标模板:

docker run -d \ --name mysql8 \ --memory="1g" \ --cpus="1.0" \ -p 3306:3306 \ ...

--memory="1g"限制容器最多使用 1GB 内存,--cpus="1.0"限制最多一个 CPU 核心。如果是本地开发,这个配置足够常见场景使用;如果跑复杂查询,可以适当调到 2GB。限制资源的好处是 MySQL 疯了也不至于拖垮整台机器。

启动失败的排查,我按概率排序写个清单:

症状主要原因处理方法
容器一直 Restarting数据目录权限不对、配置文件参数非法、端口被占docker logs mysql8看具体日志
Can't connect to MySQL server端口映射没生效或 3306 被占用docker ps查看端口映射,netstat排查端口
Access denied密码错、host 不匹配、认证插件不支持检查账号 host,必要时重建账号
Table 'mysql.plugin' doesn't existlower_case_table_names 初始化后变更重新初始化数据目录或恢复原配置
docker network 不通容器间网络配置问题多个 MySQL 容器使用自定义网络docker network create后互联

容器间通信是另一个常踩的坑。比如你同时用 Docker 跑 MySQL 和 Spring Boot 应用,应用容器里写localhost:3306是连不到 MySQL 容器的,因为两个容器各自有独立网络栈。正确做法是创建一个自定义网络:

docker network create mynet

启动 MySQL 时加--network mynet,启动应用容器时也加--network mynet,应用里连接地址写容器名mysql8而不是 localhost。这样 Docker 内置 DNS 会自动解析。这个细节曾经折磨过我很久,第一次遇到时我以为 MySQL 挂了,结果只是网络模式的问题。

如果你觉得docker run参数太多记不住,可以考虑用 Docker Compose,配置写在 YAML 里更直观,也方便团队共享环境。一个简版 compose 文件可以这样写:

services: mysql8: image: mysql:8.0 container_name: mysql8 restart: unless-stopped ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: "Root@123" TZ: "Asia/Shanghai" volumes: - ./mysql/data:/var/lib/mysql - ./mysql/config/my.cnf:/etc/mysql/conf.d/my.cnf

然后docker compose up -d就行。

踩过几次坑之后,我现在的习惯是:凡是涉及容器的数据库环境,先把日志、数据卷、端口映射列清楚,再动手敲命令。尤其不要凭记忆写-v路径,路径写错时容器也能启动,但数据存到了你找不到的地方,恢复和备份都会很尴尬。整套跑通后你会发现,Docker 里的 MySQL 其实比裸装更好伺候——它能随时销毁重建,配置和数据分离,环境迁移成本极低。只要把挂载、端口、认证这三件事想明白,剩下的都是套路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询