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

Docker容器中Node.js无法连接MySQL的问题求助

问题:Node.js容器无法连接MySQL容器(ECONNREFUSED)

错误信息

Express server is runnig at port no : 8000
backend-web-1  | DB connection failed
backend-web-1  |  Error : {
backend-web-1  |   "errno": -111,
backend-web-1  |   "code": "ECONNREFUSED",
backend-web-1  |   "syscall": "connect",
backend-web-1  |   "address": "127.0.0.1",
backend-web-1  |   "port": 3306,
backend-web-1  |   "fatal": true
backend-web-1  | }

相关配置文件

MySQL Dockerfile(路径:./dbinit/Dockerfile)

FROM mysql
WORKDIR /app
COPY ./mysql.sql /docker-entrypoint-initdb.d/

Node.js Dockerfile(路径:./app/Dockerfile)

FROM node:18-alpine
WORKDIR /app
COPY *package.json /app
RUN npm install
EXPOSE 8000
COPY . /app
CMD ["node" ,"index.js"]

docker-compose.yml

services: 
  db: 
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    build: ./dbinit
    environment: 
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: timesheet
      restart: always
    ports:
      - "3305:3309"
  web:
    depends_on:
      - "db"
    build: ./app
    environment:
      MYSQL_HOST: db
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: timesheet
    ports:
      - "5000:8000"

Node.js数据库连接代码(index.js)

// Create Connection
var mysqlConnection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'timesheet',
    multipleStatements: true
});

// Connecting database
mysqlConnection.connect((err) => {
    if (!err)
        console.log('DB connection succeded.');
    else
        console.log('DB connection failed \n Error : ' + JSON.stringify(err, undefined, 2));
});

app.listen(8000, () => console.log('Express server is runnig at port no : 8000'));

问题分析与解决方案

1. 核心问题:数据库地址硬编码为localhost

Docker Compose环境中,每个容器是独立网络节点,localhost指向Node.js容器自身,而非MySQL容器。虽然web服务配置了MYSQL_HOST: db环境变量,但代码未读取该变量,仍使用localhost。

修复代码:

var mysqlConnection = mysql.createConnection({
    host: process.env.MYSQL_HOST || 'localhost', // 优先读取环境变量
    user: 'root',
    password: process.env.MYSQL_ROOT_PASSWORD || 'root',
    database: process.env.MYSQL_DATABASE || 'timesheet',
    multipleStatements: true
});

2. 端口映射配置错误

MySQL默认端口为3306,但db服务的ports配置为"3305:3309",既不符合默认端口,也会干扰容器间通信(容器间通过服务名直接访问默认端口即可,无需映射)。

修复docker-compose.yml:

# 若需要宿主机访问MySQL,修正端口映射
ports:
  - "3305:3306"
# 若不需要宿主机访问,可直接删除ports配置项

3. 额外问题:数据库未就绪时Node.js已启动

depends_on仅保证启动顺序,不保证MySQL完成初始化并接受连接,Node.js可能在数据库未就绪时发起连接导致失败。

可选修复方案:

  • 添加重连逻辑:
function handleDisconnect() {
    mysqlConnection = mysql.createConnection({
        host: process.env.MYSQL_HOST || 'localhost',
        user: 'root',
        password: process.env.MYSQL_ROOT_PASSWORD || 'root',
        database: process.env.MYSQL_DATABASE || 'timesheet',
        multipleStatements: true
    });

    mysqlConnection.connect((err) => {
        if (err) {
            console.log('DB connection failed, retrying in 2 seconds...', err);
            setTimeout(handleDisconnect, 2000);
        } else {
            console.log('DB connection succeeded.');
        }
    });

    mysqlConnection.on('error', (err) => {
        console.log('DB error occurred, reconnecting...', err);
        if (err.code === 'PROTOCOL_CONNECTION_LOST') {
            handleDisconnect();
        } else {
            throw err;
        }
    });
}

handleDisconnect();
  • 使用工具等待数据库就绪:
    1. 修改Node.js Dockerfile安装wait-for-it:
      RUN apk add --no-cache bash
      COPY https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /usr/local/bin/wait-for-it.sh
      RUN chmod +x /usr/local/bin/wait-for-it.sh
      
    2. 更新web服务的启动命令:
      command: ["wait-for-it.sh", "db:3306", "--", "node", "index.js"]
      

内容的提问来源于stack exchange,提问作者Sherwin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:31:11