先拉镜像

docker pull mysql:8.0

创建 MySQL 数据目录(防止容器删除数据丢失)

mkdir -p ~/docker/mysql8/data
mkdir -p ~/docker/mysql8/conf
mkdir -p ~/docker/mysql8/logs

创建 MySQL 配置文件(关键!!)

cd ~/docker/mysql8/conf
vim my.cnf

写入:

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

# 允许远程访问
bind-address=0.0.0.0

# 解决 Navicat 连接失败
default-authentication-plugin=mysql_native_password

运行 MySQL8 容器

docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ~/docker/mysql8/data:/var/lib/mysql \
-v ~/docker/mysql8/conf:/etc/mysql/conf.d \
-v ~/docker/mysql8/logs:/logs \
--restart always \
mysql:8.0

说明:

参数含义
-p 3306:3306 映射端口(Windows 才能访问)
MYSQL_ROOT_PASSWORD root密码
-v 数据持久化
–restart always 开机自动启动

查看是否成功:

docker ps

看到:

mysql8   mysql:8.0   Up (healthy)

进入 MySQL 测试

docker exec -it mysql8 mysql -uroot -p

输入密码即可进入mysql

允许远程访问(Windows Navicat 能连的关键)

在 mysql 里执行:

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;

然后退出:
exit;

异常问题处理

错误1:

执行下面的语句时 docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -v ~/docker/mysql8/data:/var/lib/mysql \ -v ~/docker/mysql8/conf:/etc/mysql/conf.d \ -v ~/docker/mysql8/logs:/logs \ --restart always \ mysql:8.0 出现了如下错误提示
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint mysql8 (db046c0d78855840cc051ffd10ae9acf3dcd87970b308fcc1a647f1c022dcf15): failed to bind host port 0.0.0.0:3306/tcp: address already in use
解决办法
这个错误其实非常典型,而且不是 Docker 问题,是你的 Ubuntu 已经有人在占用 3306 端口了 👇

failed to bind host port 0.0.0.0:3306: address already in use

含义:

Docker 想把「宿主机的 3306」映射给容器,但宿主机本身已经有程序在监听 3306,所以 Docker 绑定失败。

也就是说:

你的 Ubuntu 里已经装过 MySQL / MariaDB(系统自带的最常见)

Ubuntu 24.04 安装某些软件(如 php、mariadb-client、lamp、甚至某些桌面组件)时,会自动带一个数据库服务。


第一步:确认谁占用了 3306

执行:

sudo ss -lntp | grep 3306

你大概率会看到类似:

LISTEN 0 70 127.0.0.1:3306  0.0.0.0:*  users:(("mysqld",pid=1234,fd=22))

或者:

("mariadbd",pid=xxxx)

这就说明 ——
系统自带 MySQL/MariaDB 正在运行

(这也是为什么 Docker MySQL 起不来)


第二步(推荐做法):彻底关闭并卸载系统 MySQL ⭐⭐⭐

我们既然用 Docker,就不要系统 MySQL,否则你以后一定混乱(端口、数据目录、权限、socket 全冲突)。

1)先停止服务

sudo systemctl stop mysql
sudo systemctl stop mariadb

再确认:

sudo ss -lntp | grep 3306

如果没输出,说明端口已释放。


2)禁用开机启动

sudo systemctl disable mysql
sudo systemctl disable mariadb

3)彻底卸载(强烈建议)

sudo apt purge -y mysql-server mysql-client mysql-common mariadb-server mariadb-client mariadb-common

清理残留数据库(很关键):

sudo rm -rf /var/lib/mysql
sudo rm -rf /etc/mysql

自动清理依赖:

sudo apt autoremove -y
sudo apt autoclean

再次确认端口:

sudo ss -lntp | grep 3306

现在必须没有任何输出。


第三步:重新启动 Docker MySQL

现在重新执行你刚才那条命令:

docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ~/docker/mysql8/data:/var/lib/mysql \
-v ~/docker/mysql8/conf:/etc/mysql/conf.d \
-v ~/docker/mysql8/logs:/logs \
--restart always \
mysql:8.0

然后:

docker ps

如果看到:

mysql8   mysql:8.0   Up xx seconds

说明容器已经成功启动 🎉


如果你不想卸载(不推荐)

可以改端口,例如:

-p 3307:3306

那 Windows Navicat 就要连:

IP: 192.168.x.x
Port: 3307

但我非常不建议,因为以后你一定会忘记哪个是系统 MySQL,哪个是 Docker MySQL,开发会很痛苦。


下一步(很重要)

容器启动后,立刻测试:

docker logs mysql8

如果看到:

ready for connections
port: 3306

再进行 Navicat 连接,否则先别连(很多人这一步没做导致误判)。

ss -lntp | grep 3306 的输出贴给我,我可以直接帮你判断你机器现在的状态。

错误2

qwer@qwer-virtual-machine:~/docker/mysql8/conf$ docker run -d
–name mysql8
-p 3306:3306
-e MYSQL_ROOT_PASSWORD=123456
-v ~/docker/mysql8/data:/var/lib/mysql
-v ~/docker/mysql8/conf:/etc/mysql/conf.d
-v ~/docker/mysql8/logs:/logs
–restart always
mysql:8.0
docker: Error response from daemon: Conflict. The container name “/mysql8” is already in use by container “2a17c33aec952a078df8f2a165b81576a5c9312875520586ccee6e63ab1a512d”. You have to remove (or rename) that container to be able to reuse that name.

Run ‘docker run --help’ for more information

很好 👍
这个状态已经把问题完全暴露出来了

STATUS: Created

注意这不是 Exited,也不是 Up

这在 Docker 里是一个非常关键的状态

Created = 容器对象已经创建成功,但容器一次都没有真正启动成功过(mysqld 甚至还没来得及运行)

也就是说:
你第一次因为 3306 端口冲突 失败时,Docker 只创建了容器外壳,MySQL 初始化没有完成,所以现在它卡死了。

这也是 Docker MySQL 新手最常见卡点。


必须做的三步(顺序不能错)

① 强制删除这个“半死不活”的容器

直接删:

docker rm -f mysql8

再确认:

docker ps -a

现在应该没有 mysql8


② 清空 MySQL 数据目录(这是关键!!!)

因为你挂载了:

-v ~/docker/mysql8/data:/var/lib/mysql

MySQL 初始化失败时,已经往里面写了残缺数据库
如果不清空,MySQL会永远启动失败(而且日志会非常迷惑)。

执行:

rm -rf ~/docker/mysql8/data/*

(不是删目录,是删里面的内容)

你可以确认一下:

ls ~/docker/mysql8/data

应该是空的。


③ 再次运行容器(但这次要盯日志)

重新执行:

docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-v ~/docker/mysql8/data:/var/lib/mysql \
-v ~/docker/mysql8/conf:/etc/mysql/conf.d \
-v ~/docker/mysql8/logs:/logs \
--restart always \
mysql:8.0

马上执行:

docker logs -f mysql8

这一步非常关键,第一次初始化需要 20~60 秒,很多人以为失败其实是在初始化 InnoDB。


正确的日志应该长这样

你会看到一大堆:

Initializing database
InnoDB initialization has started
InnoDB initialization has ended

最后必须出现这一句:

mysqld: ready for connections.
port: 3306

只要这句出现,数据库就真的活了 ✔


然后验证

docker ps

应该看到:

Up xx seconds (healthy)

接着:

docker exec -it mysql8 mysql -uroot -p

密码:

123456

能进入 mysql> 提示符,就成功了。

问题3:

Error response from daemon: Get “https://registry-1.docker.io/v2/”: context deadline exceeded
出现类似上面的网络问题,可能是两个原因
(1)docker镜像有问题
cd /etc/docker
修改daemon.json配置如下:

{
        "registry-mirrors" : [
                "https://docker.1ms.run"
        ]
}

docker镜像可能经常失效,需要去查找可用的镜像,然后重启docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker
(2)dns解析问题
cat /etc/resolv.conf
如果 DNS 是 127.0.0.53 可能解析有问题。

可以改成下面的dns
nameserver 8.8.8.8
nameserver 114.114.114.114

保存后, sudo reboot

更多推荐