Skip to main content
Back to Lab
February 28, 2016 ·
Node.jsMySQLDevelopment

Solving ETIMEDOUT Errors in Node.js MySQL Connections

How to fix MySQL connection timeout errors in long-running Node.js applications by implementing proper connection pool management.

If you’re running a long-lived Node.js application that connects to MySQL, you’ve likely encountered the dreaded ETIMEDOUT error:

Error: connect ETIMEDOUT
    at Connection._handleConnectTimeout

This typically occurs when your application has been idle for a while and MySQL has closed the connection on its end.

The Root Cause

By default, MySQL closes idle connections after a certain timeout period (typically 8 hours with wait_timeout). When your Node.js application tries to reuse a stale connection, it fails with ETIMEDOUT.

The Solution: Connection Pooling with Keep-Alive

Instead of creating single connections, use connection pooling with proper configuration:

const mysql = require('mysql2');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'your_user',
  password: 'your_password',
  database: 'your_database',
  
  // Connection pool settings
  connectionLimit: 10,
  queueLimit: 0,
  
  // Keep connections alive
  waitForConnections: true,
  enableKeepAlive: true,
  keepAliveInitialDelay: 30000, // 30 seconds
});

// Use pool.query() instead of connection.query()
pool.query('SELECT 1', (err, results) => {
  if (err) throw err;
  console.log('Connection successful');
});

Key Configuration Options

OptionDescriptionRecommended Value
connectionLimitMaximum concurrent connections10 (adjust based on load)
enableKeepAliveSend TCP keep-alive packetstrue
keepAliveInitialDelayDelay before first keep-alive30000ms
waitForConnectionsQueue requests when pool is fulltrue

For TypeScript Users

Using mysql2/promise with TypeScript:

import mysql from 'mysql2/promise';

const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  connectionLimit: 10,
  enableKeepAlive: true,
  keepAliveInitialDelay: 30000,
});

async function query<T>(sql: string, params?: any[]): Promise<T> {
  const [rows] = await pool.execute(sql, params);
  return rows as T;
}

export { pool, query };

Alternative: Connection Ping

If you can’t use connection pooling, implement a periodic ping to keep connections alive:

setInterval(() => {
  connection.ping((err) => {
    if (err) {
      console.error('MySQL ping failed:', err);
      // Reconnect logic here
    }
  });
}, 60000); // Every 60 seconds

Conclusion

Connection pooling with enableKeepAlive is the most robust solution for production Node.js applications. It handles connection lifecycle automatically and prevents timeout issues without manual intervention.


Questions about Node.js database connectivity? Feel free to reach out.