# 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:
Error: connect ETIMEDOUT
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)Or:
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:
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.Diagnosis revealed multiple issues:
- 2.Security group didn't allow traffic from all application subnets
- 3.Connection pool timeout was too short (5 seconds)
- 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:
[
{
"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:
aws ec2 authorize-security-group-ingress \
--group-id sg-abc12345 \
--protocol tcp \
--port 3306 \
--cidr 10.0.0.0/16Step 3: Verify RDS Instance Status
aws rds describe-db-instances \
--db-instance-identifier production-db \
--query 'DBInstances[0].[DBInstanceStatus,Endpoint.Address,Endpoint.Port,StorageEncrypted]'Output:
[
"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
mysql -h production-db.xxxxx.us-east-1.rds.amazonaws.com \
-u admin \
-p \
-e "SELECT 1 as test;"If this fails with:
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:
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:
# 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:
# 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:
SHOW VARIABLES WHERE Variable_name IN (
'connect_timeout',
'wait_timeout',
'interactive_timeout',
'net_read_timeout',
'net_write_timeout',
'lock_wait_timeout'
);Output:
Variable_name | Value
-----------------------+-------
connect_timeout | 10
wait_timeout | 28800
interactive_timeout | 28800
net_read_timeout | 30
net_write_timeout | 60
lock_wait_timeout | 31536000Modify 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):
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 minuteNode.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:
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:
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:
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';Output:
Threads_connected: 148
max_connections: 150Increase 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:
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,MaximumSolutions: - 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):
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-8Node.js (mysql2):
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):
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):
$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.