You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器中NodeJS连接MySQL报错ECONNREFUSED求助

NodeJS应用连接MySQL时出现ECONNREFUSED 3306错误的排查与解决

使用Docker Compose部署NodeJS应用和MySQL服务后,执行docker compose up,NodeJS应用抛出连接拒绝错误,目标端口为3306,但Adminer可以正常连接MySQL。相关配置及代码如下:

Docker Compose配置

services:
  app-node:
    build: .
    ports: 
      - "3000:3000"
    depends_on:
      mysql2:
        condition: service_healthy
        restart: true
    environment:
      DB_HOST: mysql2
      DB_USER: lucasfer
      DB_PASSWORD: contra31
      DB_NAME: test-docker
      DB_PORT: "3308"

  mysql2:
    image: mysql:5.7.27
    healthcheck:
      test: "exit 0"
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    ports: 
    - "3308:3308"
    environment:
      MYSQL_ROOT_PASSWORD: contra31
      MYSQL_DATABASE: test-docker
      MYSQL_USER: lucasfer
      MYSQL_PASSWORD: contra31

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

NodeJS Dockerfile

FROM node:18-alpine3.18

WORKDIR /app
COPY . .

RUN npm install
RUN npm run build

EXPOSE 3000

ENTRYPOINT ["node", "./dist/index.js"]

NodeJS应用代码

import express, { Request, Response } from 'express'
import mysql from 'mysql'
import { createUserTable, insertInitialUsers } from './src/DatabaseService.js'; 

const pool = mysql.createPool({
    connectionLimit : 10,
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    port: Number(process.env.DB_PORT)
});

const app = express()
const PORT = 3000;

createUserTable(pool)
insertInitialUsers(pool)


app.get('/', async (req: Request, res: Response) => {
    pool.query('SELECT * FROM users', (err: any, results: any) => {
        if (err) {
            console.error(err)
            return res.status(500).json({ error: 'Database error' })
        }
        res.json(results)
    })
})


app.listen(PORT, () => {
    console.log(`Servidor NodeJS corriendo en puerto ${PORT}`)
})

数据库服务文件

import { Pool } from "mysql";
export function createUserTable (pool: Pool) {
    pool.query(`
        CREATE TABLE IF NOT EXISTS users(
            id INT AUTO_INCREMENT PRIMARY KEY,
            firstName VARCHAR(255),
            lastName  VARCHAR(255),
            email     VARCHAR(255)      
        )
    ` , (err, result) => {
        if (err) {
            console.error(err)
            return
        }
        console.log('Tabla users creada exitosamente')
    })
}

export function insertInitialUsers (pool: Pool) {
    return pool.query(`
        INSERT INTO users(firstName, lastName, email)
        VALUES  ('Lucas', 'Ferrero', 'lucasdavidferrero@gmail.com'),
                ('Juan', 'Perez', 'juanperez@gmail.com'),
                ('Pedro', 'PicaPiedra', 'pedrito@gmail.com')
    `, (err, result) => {
        if (err) {
            console.error(err)
            return
        }
        console.log('usuarios insertados correctamente')
    })
}

报错信息

Error: connect ECONNREFUSED 172.21.0.3:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
    --------------------
    at Protocol._enqueue (/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/app/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/app/node_modules/mysql/lib/Connection.js:116:18)
    at file:///app/dist/index.js:22:5
    at ModuleJob.run (node:internal/modules/esm/module_job:195:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:337:24)
    at async loadESM (node:internal/process/esm_loader:34:7)
    at async handleMainPromise (node:internal/run_main:106:12) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '172.21.0.3',
  port: 3306,
  fatal: true
}

错误原因分析

  1. MySQL容器端口配置错误:
    MySQL镜像默认在容器内部监听3306端口,但你的mysql2服务端口映射写的是3308:3308,这意味着试图让容器内部MySQL用3308端口启动,但MySQL未修改默认端口配置,实际仍运行在3306端口。

  2. NodeJS连接端口配置错误:
    NodeJS应用的环境变量DB_PORT设为3308,但Docker容器间通信需访问容器内部端口,而非宿主映射的端口。即使修正MySQL端口映射,NodeJS也应连接容器内的3306端口。

  3. 健康检查无效:
    mysql2服务的健康检查用test: "exit 0",这是一个始终成功的空命令,无法真正检测MySQL服务是否就绪,可能导致NodeJS在MySQL未完全启动时尝试连接,但本次报错核心问题还是端口配置。


解决方案

1. 修正MySQL服务的端口映射

将mysql2服务的ports改为3308:3306,宿主3308端口映射到容器内MySQL默认的3306端口,既不影响外部工具(如Adminer)连接,也保证容器内部服务正常访问。

2. 修改NodeJS的数据库连接端口

将app-node服务的DB_PORT环境变量改为3306,容器内部访问MySQL需用容器内的默认端口。

3. 修复MySQL健康检查

使用真实检测命令确保MySQL服务就绪,替换healthcheck配置:

healthcheck:
  test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
  timeout: 20s
  retries: 10

修改后的Docker Compose配置

services:
  app-node:
    build: .
    ports: 
      - "3000:3000"
    depends_on:
      mysql2:
        condition: service_healthy
        restart: true
    environment:
      DB_HOST: mysql2
      DB_USER: lucasfer
      DB_PASSWORD: contra31
      DB_NAME: test-docker
      DB_PORT: "3306"  # 修改为容器内MySQL默认端口

  mysql2:
    image: mysql:5.7.27
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      timeout: 20s
      retries: 10
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    ports: 
    - "3308:3306"  # 修正端口映射,宿主3308→容器3306
    environment:
      MYSQL_ROOT_PASSWORD: contra31
      MYSQL_DATABASE: test-docker
      MYSQL_USER: lucasfer
      MYSQL_PASSWORD: contra31

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

4. 重启服务

执行以下命令重新部署:

docker compose down
docker compose up --build

内容的提问来源于stack exchange,提问作者Lucas David Ferrero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:45:07