使用Docker/Docker-Compose连接Node.js与MySQL时遇连接拒绝问题
Node.js + MySQL Docker连接问题排查
配置文件
Dockerfile
FROM node:latest WORKDIR /app COPY . /app RUN npm update RUN npm install RUN npm rebuild bcrypt ENV SERVER_PORT 3000 EXPOSE $SERVER_PORT CMD ["npm", "start"]
docker-compose.yml
services: mysqldb: image: mysql:8.0 container_name: mysqlcontainer command: --default-authentication-plugin=mysql_native_password restart: unless-stopped volumes: - ./dbinit/init.sql:/docker-entrypoint-initdb.d/0_init.sql - $HOME/database:/var/lib/mysql ports: - 3306:3306 expose: - 3306 environment: MYSQL_DATABASE: hotel_managment MYSQL_USER: admin MYSQL_PASSWORD: letmein MYSQL_ROOT_PASSWORD: letmein SERVICE_TAGS: prod SERVICE_NAM: mysqldb networks: - internalnet nodeapp: container_name: nodeappcontainer build: . image: nodeapp:v1 ports: - 3000:3000 expose: - 3000 depends_on: - mysqldb environment: DB_HOST: mysqldb DB_USER : 'root' DB_PASSWORD: 'letmein' DB_NAME : hotel_managment DB_PORT : 3306 DB_CONNECTION_LIMIT : 10 SERVER_PORT : 3000 SERVICE_TAGS: prod SERVICE_NAME: nodeappservice networks: - internalnet networks: internalnet: driver: bridge
.env文件
DB_HOST = localhost DB_USER = root DB_PASSWORD = letmein DB_NAME = hotel_managment DB_PORT = 3306 DB_CONNECTION_LIMIT = 10 SERVER_PORT = 5000
Node.js数据库连接代码
let connection = mysql.createConnection({ host: process.env.DB_HOST, port: process.env.DB_PORT, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, });
操作与错误信息
执行命令:
docker-compose up -d --build
出现错误:
> nodejs@1.0.0 start > node -r dotenv/config app.js server is listening on port: 3000 nodejs@1.0.0 start > node -r dotenv/config app.js server is listening on port: 3000 Error connecting to database: Error: connect ECONNREFUSED 172.22.0.2:3306 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1606:16) { errno: -111, code: 'ECONNREFUSED', syscall: 'connect', address: '172.22.0.2', port: 3306, fatal: true }
排查与解决步骤
1. 解决环境变量冲突
你的docker-compose.yml给nodeapp设置了DB_HOST: mysqldb,但本地.env文件设置的DB_HOST = localhost。由于启动命令用了node -r dotenv/config app.js,dotenv会优先加载本地.env变量,覆盖docker-compose的配置,导致Node.js尝试连接容器内的localhost(而非mysqldb服务)。
解决方式三选一:
- 删除项目根目录的
.env文件,让容器使用docker-compose定义的环境变量; - 修改
.env文件的DB_HOST为mysqldb,保持与docker-compose一致; - 修改
npm start脚本为node app.js,不加载dotenv。
2. 处理MySQL初始化延迟
depends_on仅保证mysqldb容器先启动,但不保证MySQL服务完成初始化。如果MySQL初始化较慢,Node.js启动后立即连接会失败。
解决方式二选一:
- 在Node.js连接代码中添加重试逻辑:
function connectDB() { connection.connect((err) => { if (err) { console.error('连接失败,3秒后重试:', err); setTimeout(connectDB, 3000); return; } console.log('数据库连接成功'); }); } connectDB();
- 在docker-compose中添加健康检查,让nodeapp等待MySQL就绪后启动:
在mysqldb配置中添加:
healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-pletmein"] interval: 5s timeout: 5s retries: 5
修改nodeapp的depends_on:
depends_on: mysqldb: condition: service_healthy
3. 验证MySQL容器状态
- 进入MySQL容器检查服务状态:
docker exec -it mysqlcontainer mysql -uroot -pletmein # 进入后执行命令确认数据库存在 SHOW DATABASES;
- 确认MySQL容器在指定网络内:
docker inspect mysqlcontainer | grep Networks
- 检查root用户是否允许远程连接:
在MySQL中执行:
SELECT user, host FROM mysql.user;
如果root用户的host不是%,执行:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'letmein'; FLUSH PRIVILEGES;
4. 检查网络连通性
在nodeapp容器内ping MySQL容器的内网IP(错误信息中的172.22.0.2):
docker exec -it nodeappcontainer ping 172.22.0.2
如果ping不通,检查docker-compose的networks配置,确保两个服务都加入了internalnet网络。
内容的提问来源于stack exchange,提问作者octopoda
相关产品推荐
相关产品推荐

