根本原因是 MySQL 5.7 容器默认 bind-address=127.0.0.1 且 root@localhost 权限限制,导致其他容器无法远程连接;必须挂载自定义 my.cnf 设置 bind-address=0.0.0.0 和 lower_case_table_names=1,并创建 @'%' 用户授权。

直接上结论:用 docker run 启动一个带自定义配置、开放远程连接、自动初始化用户和库的 MySQL 5.7 容器,必须显式挂载 my.cnf 并设置 bind-address = 0.0.0.0 和 lower_case_table_names = 1,否则 Spring Boot 服务连不上或 JPA 映射失败。
为什么默认 docker run mysql:5.7 连不上其他微服务?
根本原因不是端口没映射,而是 MySQL 容器默认只监听 127.0.0.1,且 root 用户默认只允许本地连接。微服务(比如 user-service)运行在另一个容器里,IP 是类似 172.18.0.3 的内网地址,一连就报:Host '172.18.0.3' is not allowed to connect to this MySQL server。
- 查日志确认:
docker logs mysql,看到上面那句错误就坐实了权限+绑定地址问题 -
bind-address = 127.0.0.1是 MySQL 5.7 镜像的默认值,不改就只能本机(容器内部)连 - 不创建
@'%'用户,JDBC URL 里的jdbc:mysql://mysql:3306/mydb中的mysql别名解析成功也没用——拒绝访问
如何用一条命令启动可被微服务直连的 MySQL 5.7?
关键不在“拉镜像”,而在“启动时绕过默认限制”。推荐用以下结构化命令,含必要挂载和初始化:
docker run -d \ --name mysql57 \ --network mynet \ -p 3306:3306 \ -v $(pwd)/mysql/conf:/etc/mysql/conf.d \ -v $(pwd)/mysql/data:/var/lib/mysql \ -v $(pwd)/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql \ -e MYSQL_ROOT_PASSWORD=root \ -e MYSQL_DATABASE=devdb \ mysql:5.7
-
--network mynet:必须提前docker network create mynet,否则默认bridge网络下容器 DNS 解析不到mysql这个别名 -
/etc/mysql/conf.d/下放custom.cnf,内容至少含:[mysqld]bind-address = 0.0.0.0lower_case_table_names = 1default-time-zone = '+08:00' -
/docker-entrypoint-initdb.d/init.sql会在首次启动时执行,建议包含:CREATE USER 'svc'@'%' IDENTIFIED BY 'svc123'; GRANT ALL ON devdb.* TO 'svc'@'%'; FLUSH PRIVILEGES; - 别用
-e MYSQL_ALLOW_EMPTY_PASSWORD=yes,它不解决@'%'权限问题,反而埋下安全坑
Spring Boot 服务连 MySQL 的 JDBC URL 怎么写?
URL 不是 localhost 或宿主机 IP,而是 Docker 网络内的服务名——前提是两者在同一个 --network 下。
- 正确写法:
jdbc:mysql://mysql57:3306/devdb?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=GMT%2B8 -
mysql57是容器名,Docker 自动注册为 DNS 名,user-service容器能直接解析 - 必须加
serverTimezone=GMT%2B8,否则 Java 8+ 会抛java.time.format.DateTimeParseException - 如果用 HikariCP,记得设
spring.datasource.hikari.connection-timeout=3000,避免启动时因 MySQL 慢启动导致服务卡死
数据持久化与多服务共用时的隔离要点
本地开发阶段,多个微服务(如 order、payment)共享一个 MySQL 实例是常态,但不能共用表;靠 database 隔离最轻量,也最易调试。
- 初始化 SQL 里建多个库:
CREATE DATABASE order_db;、CREATE DATABASE payment_db; - 给每个服务分配独立用户 + 库级权限:
GRANT ALL ON order_db.* TO 'order_svc'@'%'; - 挂载的
/var/lib/mysql目录必须是空的或已有兼容数据,否则容器启动失败并报错:MySQL Daemon failed to start - 不要用
rm -rf直接删挂载目录再重跑容器——InnoDB 的ibdata1文件残留会导致崩溃,应先docker stop mysql57 && docker rm mysql57,再清空目录
真正容易被忽略的是:MySQL 容器首次启动后,/docker-entrypoint-initdb.d/ 下的 SQL 只执行一次;后续重启不会重跑。所以改权限、加库、调参数,要么进容器手动执行,要么删容器重建——而重建前,必须确认 /var/lib/mysql 挂载点没被其他进程占用,否则 chown -R mysql:mysql 失败,MySQL 就起不来。


















