Docker化全栈项目:Node.js API连MySQL容器遇ECONNREFUSED错误求助
问题与需求
我正在开发MySQL数据库+Express API的全栈项目,本地运行正常,Docker化后遇到以下问题:
- Node.js API连接MySQL容器时抛出
ECONNREFUSED错误(主机可通过MySQL Workbench正常连接) - 临时通过修改MySQL容器默认认证插件为
mysql_native_password解决了连接问题,但该方案已弃用,希望适配MySQL 8.0默认的caching_sha2_password认证方案 - 首次启动时需手动重启node_api容器,因MySQL启动耗时更长
我的完整docker-compose.yml配置如下:
version: '3' services: db: image: mysql:latest command: --bind-address='0.0.0.0' container_name: mysql_db ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: housesdb MYSQL_PASSWORD: password volumes: - app-data:/var/lib/mysql networks: - my-network api: build: ./Backend container_name: node_api ports: - "3005:3005" environment: DB_HOST: db DB_PORT: 3306 DB_USER: root DB_PASSWORD: password DB_NAME: housesdb depends_on: - db networks: - my-network web: build: ./frontend-jm container_name: react_app ports: - "3000:3000" depends_on: - db - api networks: - my-network networks: my-network: driver: bridge volumes: app-data:
排查过程中,我尝试执行SQL切换认证插件:
alter user 'root'@'%' identified with mysql_native_password by 'password'
得到错误:
Error Code: 1524. Plugin 'mysql_native_password' is not loaded
最优解决方案
一、适配caching_sha2_password认证方案
1. 升级Node.js MySQL客户端
停止使用已停止维护的mysql包,改用mysql2包(原生支持caching_sha2_password):
# 在Backend目录执行 npm install mysql2
2. 修改API连接代码
使用mysql2/promise建立连接池,无需额外配置即可自动适配caching_sha2_password:
const mysql = require('mysql2/promise'); // 创建连接池 const pool = mysql.createPool({ 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, waitForConnections: true, connectionLimit: 10, queueLimit: 0 }); // 测试连接示例 async function testConnection() { try { const [rows] = await pool.query('SELECT 1 + 1 AS solution'); console.log('数据库连接成功:', rows[0].solution); } catch (err) { console.error('连接失败:', err); } } testConnection();
3. 确认MySQL用户配置
MySQL 8.0默认用caching_sha2_password创建root用户,无需修改。若需创建专用应用用户,执行以下SQL:
CREATE USER 'app_user'@'%' IDENTIFIED BY 'your_secure_password'; GRANT ALL PRIVILEGES ON housesdb.* TO 'app_user'@'%'; FLUSH PRIVILEGES;
之后修改API环境变量中的DB_USER为app_user即可。
二、解决容器启动顺序问题
depends_on仅保证容器启动顺序,不保证MySQL服务就绪,需通过健康检查或等待脚本解决:
方案1:Docker健康检查(推荐)
修改docker-compose.yml中db服务的配置,添加健康检查,让api服务等待db健康后再启动:
services: db: image: mysql:latest container_name: mysql_db ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: housesdb MYSQL_PASSWORD: password volumes: - app-data:/var/lib/mysql networks: - my-network # 添加健康检查 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"] interval: 5s # 每5秒检查一次 timeout: 5s # 超时时间5秒 retries: 5 # 重试5次后标记为不健康 api: build: ./Backend container_name: node_api ports: - "3005:3005" environment: DB_HOST: db DB_PORT: 3306 DB_USER: root DB_PASSWORD: password DB_NAME: housesdb depends_on: db: condition: service_healthy # 等待db服务健康后启动 networks: - my-network
方案2:API启动脚本添加等待逻辑
在Backend的Dockerfile中安装wait-for-it工具,修改启动脚本等待MySQL就绪:
- 修改Backend的
package.json:
"scripts": { "start": "wait-for-it db:3306 -- node server.js" }
- 修改Backend的
Dockerfile:
FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install # 安装wait-for-it RUN apk add --no-cache wait-for-it COPY . . CMD ["npm", "start"]
总结
- 使用
mysql2客户端是适配caching_sha2_password的最优方案,无需修改MySQL默认配置,符合官方推荐 - 通过Docker健康检查或启动等待脚本,可彻底解决首次启动需手动重启API容器的问题
内容的提问来源于stack exchange,提问作者Drose
相关产品推荐
相关产品推荐

