When attempting to connect to a publicly accessible RDS MySQL instance from outside its VPC, you encounter ERROR 2003 (HY000) despite having:
- Public accessibility enabled in RDS settings
- Security groups allowing all traffic (0.0.0.0/0)
- Permissive network ACLs
- No local firewall restrictions
The confusing aspect is that connectivity works perfectly from EC2 instances within the same VPC. This suggests the issue lies in the public accessibility configuration rather than database authentication or basic networking.
1. RDS Public Accessibility ≠ Internet Access
The "Publicly Accessible" flag in RDS settings merely assigns a public IP. It doesn't automatically configure the full path for external access. Verify with:
aws rds describe-db-instances --db-instance-identifier your-instance \
--query 'DBInstances[0].PubliclyAccessible'
2. Subnet Routing Requirements
The RDS instance must reside in a public subnet with:
- Route table containing an Internet Gateway (IGW) route
- Auto-assign public IP enabled for the subnet
Check subnet configuration:
aws ec2 describe-subnets --subnet-ids your-subnet-id \
--query 'Subnets[0].MapPublicIpOnLaunch'
3. Security Group Misconfiguration Patterns
While your security group shows 0.0.0.0/0 access, verify it's attached to the RDS instance:
aws rds describe-db-instances --db-instance-identifier your-instance \
--query 'DBInstances[0].VpcSecurityGroups'
Network Path Verification
From your external machine, run these connectivity tests:
# Check basic reachability
telnet mysql1.xxxxxxxxxxxx.eu-west-1.rds.amazonaws.com 3306
# Test DNS resolution
dig +short mysql1.xxxxxxxxxxxx.eu-west-1.rds.amazonaws.com
# Network traceroute (Linux/Mac)
traceroute -T -p 3306 mysql1.xxxxxxxxxxxx.eu-west-1.rds.amazonaws.com
AWS-Specific Checks
Examine VPC Flow Logs for rejected connections:
aws ec2 create-flow-logs --resource-type VPC --resource-id your-vpc-id \
--traffic-type REJECT --log-destination-type cloud-watch-logs \
--log-group-name "VPCRejectLogs"
If you've confirmed the RDS instance is in a private subnet (the most common issue), you have two approaches:
Option 1: Move to Public Subnet
- Create a new DB subnet group with public subnets
- Modify the RDS instance to use this subnet group
aws rds modify-db-instance --db-instance-identifier your-instance \
--db-subnet-group new-public-subnet-group --apply-immediately
Option 2: Set Up Bastion Host
For better security, maintain the private subnet setup and use SSH tunneling:
ssh -i your-key.pem -N -L 3306:your-rds-endpoint:3306 ec2-user@your-bastion-public-ip
Then connect locally:
mysql -h 127.0.0.1 -u skullberry -p
After making changes, verify connectivity from external networks using:
nc -zv mysql1.xxxxxxxxxxxx.eu-west-1.rds.amazonaws.com 3306
Remember that DNS changes might take a few minutes to propagate after modifying RDS network settings.
When attempting to connect to an AWS RDS MySQL instance from outside its VPC, you're encountering Error 2003 (HY000) despite having:
- Public accessibility enabled
- Security groups configured to allow all traffic
- Network ACLs permitting all traffic
The most common oversight in such scenarios is the RDS instance's subnet group configuration. Even with public accessibility enabled, the RDS instance must be placed in a public subnet with:
- An Internet Gateway attached to the VPC
- Proper route table configuration
Here's how to verify your subnet configuration:
# Check route tables for your subnets
aws ec2 describe-route-tables --filters "Name=vpc-id,Values=vpc-xxxxxxxx" --query "RouteTables[*].{SubnetAssociations:Associations[?SubnetId].SubnetId, Routes:Routes}"
Let's implement a step-by-step fix for this issue:
1. Verify subnet attributes:
# List your subnets and their attributes
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-xxxxxxxx" \
--query "Subnets[*].{SubnetId:SubnetId, MapPublicIpOnLaunch:MapPublicIpOnLaunch, \
RouteTable:RouteTableAssociationSet[0].RouteTableId}"
2. Modify the RDS instance's subnet group:
# Check current DB subnet group
aws rds describe-db-subnet-groups --db-subnet-group-name your-subnet-group
# Create new subnet group if needed (include public subnets)
aws rds create-db-subnet-group \
--db-subnet-group-name public-subnet-group \
--db-subnet-group-description "Public subnets for RDS" \
--subnet-ids subnet-xxxxxx1 subnet-xxxxxx2
For more secure alternatives to public accessibility, consider:
- SSH tunneling through a bastion host
- VPC peering for cross-account access
- AWS Client VPN for secure connections
Example SSH tunnel setup:
# Establish SSH tunnel to bastion host
ssh -N -L 63306:your-rds-endpoint:3306 ec2-user@your-bastion-host \
-i ~/.ssh/your-key.pem
# Connect through the tunnel
mysql -h 127.0.0.1 -P 63306 -u dbuser -p
While solving the connectivity issue, don't compromise security:
- Restrict security group rules to specific IP ranges
- Enable SSL/TLS for MySQL connections
- Implement IAM database authentication
Example security group modification:
# Update security group to allow specific IP
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxx \
--protocol tcp \
--port 3306 \
--cidr 203.0.113.24/32