# Fix Amazon RDS MySQL Connection Timeout Issues

Your application logs show connection errors:

``` com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. ```

Or:

bash
Error: connect ETIMEDOUT
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)

Or:

bash
java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

These errors indicate the application cannot establish or maintain a connection to the RDS MySQL instance.

Real Scenario: Intermittent Connection Failures

A healthcare application experienced intermittent database connection failures. The errors occurred randomly throughout the day, with no pattern. Sometimes 5% of requests failed, sometimes 20%.

Initial error from application logs:

bash
2026-04-23 14:32:15 ERROR [HikariPool-1] - Connection is not available, request timed out after 30000ms.
2026-04-23 14:32:15 WARN  [http-nio-8080-exec-45] - Unhandled exception: org.springframework.dao.DataAccessResourceFailureException
  1. 1.Diagnosis revealed multiple issues:
  2. 2.Security group didn't allow traffic from all application subnets
  3. 3.Connection pool timeout was too short (5 seconds)
  4. 4.No SSL configuration, causing handshake issues

Diagnosis Steps

Step 1: Test Basic Network Connectivity

```bash # Test DNS resolution nslookup production-db.xxxxx.us-east-1.rds.amazonaws.com

# Expected output: # Server: 10.0.0.2 # Address: 10.0.0.2#53 # Non-authoritative answer: # Name: production-db.xxxxx.us-east-1.rds.amazonaws.com # Address: 10.0.5.123 ```

If DNS fails, check: - VPC DNS is enabled (enableDnsSupport and enableDnsHostnames) - The RDS instance is in a public subnet (if accessing from outside VPC)

```bash # Test TCP connectivity (port 3306 for MySQL) nc -zv production-db.xxxxx.us-east-1.rds.amazonaws.com 3306

# Expected output: # Connection to production-db.xxxxx.us-east-1.rds.amazonaws.com 3306 port [tcp/mysql] succeeded! ```

If this times out, the security group is blocking access.

```bash # Test with telnet for more details telnet production-db.xxxxx.us-east-1.rds.amazonaws.com 3306

# Expected output: # Connected to production-db.xxxxx.us-east-1.rds.amazonaws.com. # Escape character is '^]'. # J 5.7.41-log�)Q!���>m!��#���{mysql_native_password ```

If you see the MySQL handshake, network connectivity is working.

Step 2: Check Security Group Rules

```bash # Get the security group ID for your RDS instance aws rds describe-db-instances \ --db-instance-identifier production-db \ --query 'DBInstances[0].VpcSecurityGroups[*].VpcSecurityGroupId' \ --output text

# Output: sg-abc12345

# List inbound rules aws ec2 describe-security-groups \ --group-ids sg-abc12345 \ --query 'SecurityGroups[0].IpPermissions' ```

Output:

json
[
    {
        "FromPort": 3306,
        "IpProtocol": "tcp",
        "IpRanges": [
            {
                "CidrIp": "10.0.1.0/24",
                "Description": "App subnet A"
            }
        ],
        "ToPort": 3306
    }
]

Common issue: Only one subnet is allowed, but applications run in multiple subnets.

Fix - Add all application subnets:

```bash aws ec2 authorize-security-group-ingress \ --group-id sg-abc12345 \ --protocol tcp \ --port 3306 \ --cidr 10.0.2.0/24 # Add subnet B

aws ec2 authorize-security-group-ingress \ --group-id sg-abc12345 \ --protocol tcp \ --port 3306 \ --cidr 10.0.3.0/24 # Add subnet C ```

Or allow the entire VPC CIDR:

bash
aws ec2 authorize-security-group-ingress \
    --group-id sg-abc12345 \
    --protocol tcp \
    --port 3306 \
    --cidr 10.0.0.0/16

Step 3: Verify RDS Instance Status

bash
aws rds describe-db-instances \
    --db-instance-identifier production-db \
    --query 'DBInstances[0].[DBInstanceStatus,Endpoint.Address,Endpoint.Port,StorageEncrypted]'

Output:

json
[
    "available",
    "production-db.xxxxx.us-east-1.rds.amazonaws.com",
    3306,
    true
]

If status is not "available", the instance may be: - modifying - Apply pending modifications - rebooting - Instance is restarting - incompatible-parameters - Parameter group issue - incompatible-restore - Restore failed

Step 4: Test MySQL Connection Directly

bash
mysql -h production-db.xxxxx.us-east-1.rds.amazonaws.com \
      -u admin \
      -p \
      -e "SELECT 1 as test;"

If this fails with:

bash
ERROR 2003 (HY000): Can't connect to MySQL server on 'production-db.xxxxx.us-east-1.rds.amazonaws.com' (110)

It's a network/firewall issue.

If it fails with:

bash
ERROR 1045 (28000): Access denied for user 'admin'@'10.0.1.45' (using password: YES)

It's an authentication issue.

Common Causes and Solutions

Cause 1: Security Group Blocking Access

Symptom: Connection times out after ~60 seconds with no response.

Diagnosis:

bash
# Check if your IP/security group is allowed
aws ec2 describe-security-groups \
    --group-ids sg-abc12345 \
    --filters "Name=ip-permission.to-port,Values=3306" "Name=ip-permission.from-port,Values=3306"

Solution:

```bash # Option 1: Allow specific security group (recommended for EC2-to-RDS) aws ec2 authorize-security-group-ingress \ --group-id sg-abc12345 \ --protocol tcp \ --port 3306 \ --source-group sg-app-servers

# Option 2: Allow specific CIDR aws ec2 authorize-security-group-ingress \ --group-id sg-abc12345 \ --protocol tcp \ --port 3306 \ --cidr 10.0.0.0/16

# Option 3: Allow from anywhere (NOT recommended for production) aws ec2 authorize-security-group-ingress \ --group-id sg-abc12345 \ --protocol tcp \ --port 3306 \ --cidr 0.0.0.0/0 ```

Cause 2: VPC Subnet Configuration

Symptom: EC2 instance in private subnet cannot reach RDS.

Diagnosis:

```bash # Get RDS subnet group aws rds describe-db-instances \ --db-instance-identifier production-db \ --query 'DBInstances[0].DBSubnetGroup.DBSubnetGroupName'

# Get subnets in the group aws rds describe-db-subnet-groups \ --db-subnet-group-name default-vpc-12345 \ --query 'DBSubnetGroups[0].Subnets[*].SubnetIdentifier' ```

Check route tables:

bash
# Get route table for your subnet
aws ec2 describe-route-tables \
    --filters "Name=association.subnet-id,Values=subnet-abc123"

Common issues: - RDS in private subnet, EC2 in different private subnet with no route - RDS in public subnet but PubliclyAccessible is false - NAT Gateway issues for cross-AZ traffic

Cause 3: Connection Timeout Parameters

Symptom: Connections fail during high load or long queries.

Check MySQL timeout settings:

sql
SHOW VARIABLES WHERE Variable_name IN (
    'connect_timeout',
    'wait_timeout',
    'interactive_timeout',
    'net_read_timeout',
    'net_write_timeout',
    'lock_wait_timeout'
);

Output:

bash
Variable_name          | Value
-----------------------+-------
connect_timeout        | 10
wait_timeout           | 28800
interactive_timeout    | 28800
net_read_timeout       | 30
net_write_timeout      | 60
lock_wait_timeout      | 31536000

Modify via RDS parameter group:

```bash # Create custom parameter group aws rds create-db-parameter-group \ --db-parameter-group-name custom-mysql8 \ --db-parameter-group-family mysql8.0 \ --description "Custom MySQL 8.0 parameters"

# Modify timeout values aws rds modify-db-parameter-group \ --db-parameter-group-name custom-mysql8 \ --parameters \ "ParameterName=connect_timeout,ParameterValue=30,ApplyMethod=immediate" \ "ParameterName=wait_timeout,ParameterValue=600,ApplyMethod=immediate" \ "ParameterName=interactive_timeout,ParameterValue=600,ApplyMethod=immediate" \ "ParameterName=net_read_timeout,ParameterValue=60,ApplyMethod=immediate" \ "ParameterName=net_write_timeout,ParameterValue=120,ApplyMethod=immediate"

# Apply to instance aws rds modify-db-instance \ --db-instance-identifier production-db \ --db-parameter-group-name custom-mysql8 \ --apply-immediately ```

Cause 4: Application Connection Pool Issues

Symptom: Intermittent timeouts, especially under load.

HikariCP (Java/Spring Boot):

yaml
spring:
  datasource:
    url: jdbc:mysql://production-db.xxxxx.rds.amazonaws.com:3306/production?useSSL=true&serverTimezone=UTC&connectTimeout=10000&socketTimeout=30000&autoReconnect=true&failOverReadOnly=false&maxReconnects=3
    username: app_user
    password: ${DB_PASSWORD}
    hikari:
      connection-timeout: 30000        # 30 seconds to get connection from pool
      maximum-pool-size: 20            # Max connections in pool
      minimum-idle: 5                  # Min idle connections
      idle-timeout: 600000             # 10 minutes before idle connection closed
      max-lifetime: 1800000            # 30 minutes max connection age
      keepalive-time: 60000            # 1 minute keepalive
      connection-test-query: SELECT 1  # Query to validate connections
      leak-detection-threshold: 60000  # Alert if connection held > 1 minute

Node.js with mysql2:

```javascript const mysql = require('mysql2/promise');

const pool = mysql.createPool({ host: 'production-db.xxxxx.rds.amazonaws.com', port: 3306, user: 'app_user', password: process.env.DB_PASSWORD, database: 'production',

// Connection pool settings waitForConnections: true, connectionLimit: 20, // Max connections in pool queueLimit: 0, // Unlimited queue

// Timeout settings connectTimeout: 30000, // 30 seconds to connect acquireTimeout: 30000, // 30 seconds to get from pool timeout: 60000, // 1 minute query timeout

// Keep-alive enableKeepAlive: true, keepAliveInitialDelay: 10000, // 10 seconds

// SSL ssl: { ca: fs.readFileSync('/path/to/rds-ca.pem') } }); ```

Python with PyMySQL:

```python import pymysql from pymysql import Error from dbutils.pooled_db import PooledDB

# Create connection pool pool = PooledDB( creator=pymysql, maxconnections=20, mincached=5, maxcached=10, maxshared=3, blocking=True, ping=1, # Ping before use

# Connection parameters host='production-db.xxxxx.rds.amazonaws.com', port=3306, user='app_user', password=os.environ['DB_PASSWORD'], database='production',

# Timeouts connect_timeout=30, read_timeout=60, write_timeout=60,

# SSL ssl={ 'ca': '/path/to/rds-ca.pem' } )

def get_connection(): return pool.connection() ```

Cause 5: SSL/TLS Configuration Issues

Symptom: SSL connection error or connection hangs during handshake.

Download RDS CA certificate:

```bash # Download the RDS CA bundle wget -O /etc/ssl/certs/rds-ca-2019-root.pem \ https://s3.amazonaws.com/rds-downloads/rds-ca-2019-root.pem

# For newer regions, use: wget -O /etc/ssl/certs/global-bundle.pem \ https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem ```

Java JDBC with SSL:

java
String url = "jdbc:mysql://production-db.xxxxx.rds.amazonaws.com:3306/production" +
    "?useSSL=true" +
    "&requireSSL=true" +
    "&verifyServerCertificate=true" +
    "&trustCertificateKeyStoreUrl=file:///etc/ssl/certs/rds-ca.jks" +
    "&trustCertificateKeyStorePassword=changeit";

Node.js with SSL:

javascript
const connection = await mysql.createConnection({
    host: 'production-db.xxxxx.rds.amazonaws.com',
    user: 'app_user',
    password: process.env.DB_PASSWORD,
    database: 'production',
    ssl: {
        ca: fs.readFileSync('/etc/ssl/certs/rds-ca-2019-root.pem'),
        rejectUnauthorized: true
    }
});

Cause 6: Max Connections Reached

Symptom: Too many connections error.

Check connection count:

sql
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';

Output:

bash
Threads_connected: 148
max_connections: 150

Increase max connections:

```bash aws rds modify-db-parameter-group \ --db-parameter-group-name custom-mysql8 \ --parameters "ParameterName=max_connections,ParameterValue=300,ApplyMethod=pending-reboot"

# Reboot required aws rds reboot-db-instance --db-instance-identifier production-db ```

Cause 7: High CPU or Memory Pressure

Symptom: Timeouts during peak load, slow queries.

Check CloudWatch metrics:

bash
aws cloudwatch get-metric-statistics \
    --namespace AWS/RDS \
    --metric-name CPUUtilization \
    --dimensions Name=DBInstanceIdentifier,Value=production-db \
    --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
    --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
    --period 300 \
    --statistics Average,Maximum

Solutions: - Scale up instance class (db.r5.large → db.r5.xlarge) - Add read replicas for read traffic - Enable Performance Insights for query analysis - Optimize slow queries

Connection String Examples by Language

Java (JDBC):

bash
jdbc:mysql://production-db.xxxxx.rds.amazonaws.com:3306/production?useSSL=true&requireSSL=true&serverTimezone=UTC&connectTimeout=10000&socketTimeout=30000&autoReconnect=true&failOverReadOnly=false&maxReconnects=3&useUnicode=true&characterEncoding=UTF-8

Node.js (mysql2):

javascript
const config = {
    host: 'production-db.xxxxx.rds.amazonaws.com',
    port: 3306,
    user: 'app_user',
    password: process.env.DB_PASSWORD,
    database: 'production',
    connectTimeout: 30000,
    ssl: { ca: fs.readFileSync('/etc/ssl/certs/rds-ca-2019-root.pem') }
};

Python (PyMySQL):

python
connection = pymysql.connect(
    host='production-db.xxxxx.rds.amazonaws.com',
    port=3306,
    user='app_user',
    password=os.environ['DB_PASSWORD'],
    database='production',
    connect_timeout=30,
    read_timeout=60,
    write_timeout=60,
    ssl={'ca': '/etc/ssl/certs/rds-ca-2019-root.pem'}
)

PHP (PDO):

php
$dsn = "mysql:host=production-db.xxxxx.rds.amazonaws.com;port=3306;dbname=production;charset=utf8mb4";
$options = [
    PDO::ATTR_TIMEOUT => 30,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_PERSISTENT => false,
    PDO::MYSQL_ATTR_SSL_CA => '/etc/ssl/certs/rds-ca-2019-root.pem',
    PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
];
$pdo = new PDO($dsn, 'app_user', $_ENV['DB_PASSWORD'], $options);

Go (go-sql-driver):

```go import ( "database/sql" _ "github.com/go-sql-driver/mysql" )

dsn := "app_user:password@tcp(production-db.xxxxx.rds.amazonaws.com:3306)/production" + "?timeout=30s" + "&readTimeout=60s" + "&writeTimeout=60s" + "&tls=true" + "&parseTime=true" + "&charset=utf8mb4"

db, err := sql.Open("mysql", dsn) ```

Prevention Checklist

  • [ ] Security group allows traffic from all application subnets
  • [ ] Connection pool configured with appropriate timeouts (30s connect, 60s query)
  • [ ] SSL/TLS enabled for encrypted connections
  • [ ] CloudWatch alarms for connection count and CPU
  • [ ] Read replicas for scaling read traffic
  • [ ] Connection retry logic with exponential backoff
  • [ ] Health checks for connection pool validation
  • [ ] Proper connection cleanup in application code
  • [ ] Parameter group with tuned timeout values
  • [ ] Monitoring for slow queries (Performance Insights)

Emergency: Test from Inside VPC

If external tests fail, test from an EC2 instance in the same VPC:

```bash # SSH to EC2 instance ssh ec2-user@i-abc123

# Install MySQL client sudo yum install -y mysql # Amazon Linux # or sudo apt-get install -y mysql-client # Ubuntu

# Test connection mysql -h production-db.xxxxx.rds.amazonaws.com \ -u admin -p \ -e "SELECT @@version;" ```

This isolates whether the issue is network-related or application-related.