AWS RDS Connection Timeout: 6 Causes and Fixes for Production
RDS connection timeout in production? These 6 fixes cover security group rules, VPC subnet routing, parameter group connection limits, max_connections exceeded, SSL/TLS misconfig, and connection pool exhaustion ā with exact AWS CLI commands.
RDS connection timeouts are frustrating because they can come from 6 different layers. Here is a systematic debugging approach from the most to least common cause.
Quick First Steps
# Test connectivity from EC2/ECS in same VPC
psql -h your-rds-endpoint.ap-south-1.rds.amazonaws.com -U postgres -d mydb -c "SELECT 1;"
# If no psql, use nc to test TCP connectivity
nc -zv your-rds-endpoint.ap-south-1.rds.amazonaws.com 5432
# "succeeded" = network is fine, problem is elsewhere
# timeout/refused = network/security group issueCause 1: Security Group Not Allowing Inbound Traffic
The most common cause. RDS security group does not allow inbound from your application.
# Get RDS security group
aws rds describe-db-instances \
--db-instance-identifier mydb \
--query 'DBInstances[0].VpcSecurityGroups'
# Check its inbound rules
aws ec2 describe-security-groups \
--group-ids sg-0abc123 \
--query 'SecurityGroups[0].IpPermissions'Fix ā allow inbound from app security group:
# Get your app's security group ID first
APP_SG="sg-0xyz789" # Your app/EC2/ECS security group
RDS_SG="sg-0abc123" # Your RDS security group
aws ec2 authorize-security-group-ingress \
--group-id $RDS_SG \
--protocol tcp \
--port 5432 \
--source-group $APP_SGNever use 0.0.0.0/0 for RDS inbound ā use the specific security group of your application.
Cause 2: RDS in Private Subnet, App in Different VPC
If your app is in a different VPC (common with EKS separate VPCs), the subnets cannot route to each other.
# Check if your RDS is publicly accessible
aws rds describe-db-instances \
--db-instance-identifier mydb \
--query 'DBInstances[0].PubliclyAccessible'
# "false" = not reachable from outside VPC
# Check VPC peering or PrivateLink
aws ec2 describe-vpc-peering-connections \
--query 'VpcPeeringConnections[?Status.Code==`active`]'Fixes:
- VPC Peering (same account): Create peering between VPCs, add routes
- AWS PrivateLink: For cross-account access
- RDS Proxy: Best for Lambda/serverless ā handles connection pooling too
# Create RDS Proxy (handles both VPC routing and connection pooling)
aws rds create-db-proxy \
--db-proxy-name mydb-proxy \
--engine-family POSTGRESQL \
--auth '[{"AuthScheme": "SECRETS", "SecretArn": "arn:aws:secretsmanager:..."}]' \
--role-arn arn:aws:iam::123456789:role/rds-proxy-role \
--vpc-subnet-ids subnet-0abc subnet-0def \
--vpc-security-group-ids sg-0rdsCause 3: max_connections Exceeded
RDS PostgreSQL has a connection limit based on instance size. At ~90% usage, new connections start timing out.
-- Check current connections (run on RDS)
SELECT count(*) FROM pg_stat_activity;
-- Check max allowed
SHOW max_connections;
-- See connections by app
SELECT application_name, count(*)
FROM pg_stat_activity
GROUP BY application_name
ORDER BY count DESC;Fix ā increase max_connections:
Default max_connections for RDS is LEAST({DBInstanceClassMemory/9531392}, 5000). For db.t3.micro: only ~100.
# Create or update parameter group
aws rds modify-db-parameter-group \
--db-parameter-group-name mydb-params \
--parameters "ParameterName=max_connections,ParameterValue=200,ApplyMethod=pending-reboot"
# Apply parameter group to RDS
aws rds modify-db-instance \
--db-instance-identifier mydb \
--db-parameter-group-name mydb-params \
--apply-immediatelyBetter fix ā use PgBouncer connection pooler:
# PgBouncer as Kubernetes sidecar
containers:
- name: pgbouncer
image: pgbouncer/pgbouncer:1.22
env:
- name: DATABASES_HOST
value: mydb.ap-south-1.rds.amazonaws.com
- name: DATABASES_PORT
value: "5432"
- name: POOL_MODE
value: transaction # Transaction pooling = most efficient
- name: MAX_CLIENT_CONN
value: "1000" # App connects to PgBouncer
- name: DEFAULT_POOL_SIZE
value: "20" # PgBouncer uses 20 real connectionsCause 4: SSL/TLS Certificate Issue
Since 2021, AWS RDS requires SSL for some configurations.
# Test without SSL
psql "host=mydb.ap-south-1.rds.amazonaws.com dbname=mydb user=postgres sslmode=disable"
# Test with SSL
psql "host=mydb.ap-south-1.rds.amazonaws.com dbname=mydb user=postgres sslmode=require"Application fix (Python/SQLAlchemy):
import ssl
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations("rds-ca-2019-root.pem") # Download from AWS
engine = create_engine(
DATABASE_URL,
connect_args={"ssl": ssl_context}
)Download the RDS certificate bundle:
wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pemCause 5: RDS Parameter Group ā wait_timeout or connect_timeout
# Check current timeout settings
aws rds describe-db-parameters \
--db-parameter-group-name mydb-params \
--query 'Parameters[?ParameterName==`connect_timeout` || ParameterName==`wait_timeout`]'For MySQL RDS, wait_timeout=28800 (8 hours) means idle connections get killed after 8h ā then the pool tries to use dead connections.
Fix (MySQL):
aws rds modify-db-parameter-group \
--db-parameter-group-name mydb-params \
--parameters "ParameterName=wait_timeout,ParameterValue=300,ApplyMethod=immediate"And configure your connection pool to test connections before using them:
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True, # SQLAlchemy: test connection before checkout
pool_recycle=3600, # Recycle connections every hour
)Cause 6: Connection Pool Exhaustion in App Code
Your app holds too many open connections.
# Bad ā no pool size limit
engine = create_engine(DATABASE_URL)
# Good ā explicit pool config
engine = create_engine(
DATABASE_URL,
pool_size=10, # Persistent connections
max_overflow=5, # Burst capacity
pool_timeout=30, # Wait up to 30s for a connection
pool_recycle=3600, # Recycle after 1h
pool_pre_ping=True, # Test connections before use
)Debugging Flow
Connection timeout
āāā nc -zv RDS_HOST 5432 ā FAILED?
ā āāā Security group missing inbound rule ā Fix SG
ā āāā VPC routing issue ā Add VPC peering or use RDS Proxy
āāā nc SUCCEEDED but app still fails?
āāā Check max_connections ā Add PgBouncer
āāā Check SSL requirement ā Add SSL cert
āāā Check wait_timeout ā Enable pool_pre_ping
āāā Check app pool size ā Limit pool_size
More AWS troubleshooting? Read our AWS ALB 504 gateway timeout fix and AWS EKS pods stuck pending fix.
Today I Fixed
Short real fixes from production ā posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam ā just practical engineering content.
Related Articles
AWS ALB 504 Gateway Timeout ā Every Cause and Fix (2026)
Your ALB returns 504 Gateway Timeout but the app seems fine. Here's every reason this happens ā backend timeouts, keepalive mismatches, health check failures ā and exactly how to fix each one.
AWS ALB Target Group Unhealthy ā Every Cause and Fix
Your ALB shows targets as unhealthy and traffic isn't reaching your app. Here's every reason target health checks fail and exactly how to fix each one.
AWS ALB Showing Unhealthy Targets ā How to Fix It
Fix AWS Application Load Balancer unhealthy targets. Covers health check misconfigurations, security group issues, target group problems, and EKS-specific ALB controller debugging.