Docker容器连不上MySQL,99%因localhost指向容器自身而非宿主机或另一容器;需正确配置端口映射、网络、DSN地址及GORM驱动版本。

直接连不上 MySQL 容器,99% 是因为 localhost 在 Go 程序里指向容器自身,不是宿主机或另一个容器 —— 这个坑踩过一次就忘不掉。
docker run 启动 MySQL 时必须暴露端口并设好 root 密码
别用默认配置裸跑。GORM 连接失败的第一排查点就是容器根本没对外提供服务:
-
docker run -d --name mysql-db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0——-p必须有,否则 Go 程序从宿主机或另一容器都 ping 不通 - MySQL 8 默认禁用 root 远程登录,但 Docker 镜像已处理好,只要密码对、端口通,
mysql -h 127.0.0.1 -P 3306 -uroot -p123456就能进 - 如果宿主机已有 MySQL 占了 3306,把
-p 3307:3306改掉,对应 GORM 的 DSN 里 host 也要改成127.0.0.1:3307
GORM 的 DSN 中 host 不能写 localhost
在容器内运行 Go 程序时,localhost 解析为 127.0.0.1 —— 即它自己,不是 MySQL 容器。必须用 Docker 网络可识别的地址:
Docker Hub (hub.docker.com)。此技能适用于所有 Docker Hub 操作,包括读取、创建、更新和删除数据。只要任务涉及 Docker Hub,就使用此技能。
- 两个容器(Go + MySQL)用
--network mynet挂同一自定义网络,则 Go 程序 DSN 中 host 写mysql-db(即 MySQL 容器名) - Go 程序在宿主机运行,MySQL 在容器中:DSN host 写
127.0.0.1(不是localhost),端口按-p映射的实际值填 - DSN 示例:
root:123456@tcp(mysql-db:3306)/test?charset=utf8mb4&parseTime=true&loc=Local—— 注意&是 HTML 实体,代码里写&
go.mod 依赖和驱动导入必须匹配 GORM 版本
GORM v2(gorm.io/gorm)和旧版 v1(github.com/jinzhu/gorm)不兼容,驱动也不同:
- v2 必须用
gorm.io/driver/mysql,且导入方式是import "gorm.io/driver/mysql",不是下划线导入 -
go get gorm.io/gorm gorm.io/driver/mysql—— 缺一不可,少装驱动会报unsupported driver: mysql - 初始化时用
gorm.Open(mysql.Open(dsn), &gorm.Config{}),不是gorm.Open("mysql", dsn)(那是 v1 写法) - 常见错误:
database connection refused表面是连不上,实际可能是驱动没注册,err打印出来往往是空或 misleading
Dockerfile 构建 Go 二进制时要避免环境错位
别在构建阶段就硬编码数据库地址。生产部署时,连接信息应通过环境变量注入:
- Dockerfile 里不要写死
localhost:3306,改用占位符或读环境变量:os.Getenv("DB_HOST") - 启动容器时传参:
docker run -e DB_HOST=mysql-db -e DB_PORT=3306 ... - 多阶段构建更安全:
FROM golang:1.21 AS builder编译,再FROM alpine:latest运行,镜像体积小、攻击面小 - 忘记
EXPOSE 9000不影响程序监听,但会影响 docker-compose 或 K8s Service 发现 —— 如果你用编排工具,这行别省
最易被忽略的是 MySQL 容器启动后,Go 程序立即尝试连接,而 MySQL 初始化可能还没完成。加个重试逻辑或用 wait-for-it.sh 脚本垫一下,比硬 sleep 更可靠。

















