Connecting to AWS RDS MySQL from Your Local Machine: Public Access, Security Groups, and Safer Alternatives
You've just provisioned an RDS MySQL instance on AWS, opened MySQL Workbench, and hit a wall — connection refused, timeout, nothing. This is one of the most common friction points for developers new to AWS networking, and the fix requires understanding three independent gatekeepers that must all be aligned before a single TCP packet reaches your database.
TL;DR — The Three Gatekeepers
| Gatekeeper | What It Controls | What You Must Configure |
|---|---|---|
| 1. Publicly Accessible Flag | Whether RDS gets a public DNS hostname | Set to Yes for direct internet access |
| 2. VPC Security Group | Inbound/outbound firewall rules at the instance level | Allow TCP port 3306 from your IP |
| 3. VPC / Subnet Routing | Whether the subnet has a route to the Internet Gateway | RDS must be in a public subnet (has IGW route) |
All three must be correctly configured simultaneously. Fixing only one or two will still result in a timeout.
Architecture: What's Actually Happening
(MySQL Workbench)"] IGW["🌐 Internet Gateway
(VPC IGW)"] RT["📋 Route Table
0.0.0.0/0 → IGW"] SG["🛡️ Security Group
Inbound: TCP 3306"] RDS["🗄️ RDS MySQL
(Publicly Accessible: Yes)"] PublicFlag["🏷️ Public DNS
Hostname Assigned"] Laptop -->|"TCP :3306 over internet"| IGW IGW --> RT RT -->|"Routes to public subnet"| SG SG -->|"Rule matches: ALLOW"| RDS PublicFlag -.->|"Required for DNS resolution"| RDS style Laptop fill:#4A90D9,color:#fff style IGW fill:#F5A623,color:#fff style RT fill:#7ED321,color:#fff style SG fill:#D0021B,color:#fff style RDS fill:#9B59B6,color:#fff style PublicFlag fill:#1ABC9C,color:#fff
- Your Laptop initiates a TCP connection on port 3306 to the RDS public DNS endpoint.
- The request travels over the public internet to the AWS Internet Gateway (IGW) attached to your VPC.
- The IGW routes the packet to the RDS instance — but only if the instance resides in a public subnet (a subnet whose route table has a
0.0.0.0/0route pointing to the IGW). - The VPC Security Group evaluates the inbound rule. If TCP/3306 is not explicitly allowed from your source IP, the packet is silently dropped.
- The Publicly Accessible flag determines whether RDS even registers a public IP/DNS. Without it, step 2 has no destination to resolve to.
Step-by-Step: Enable Direct Public Access (Quick Path)
Use this approach for development/testing environments only. Never expose a production database directly to the internet.
Step 1 — Enable "Publicly Accessible" on the RDS Instance
- Open the RDS Console → select your DB instance → click Modify.
- Under Connectivity, set Publicly accessible to
Yes. - Choose Apply immediately and confirm. The instance will briefly restart.
- After modification, copy the Endpoint from the instance's Connectivity & security tab — it will be a public DNS name like
mydb.xxxxxxxx.us-east-1.rds.amazonaws.com.
Step 2 — Verify the Subnet is Public
A subnet is "public" only if its associated route table has an explicit route to an Internet Gateway.
- Go to VPC Console → Subnets → find the subnet(s) associated with your RDS instance's subnet group.
- Click the subnet → Route table tab → confirm a route exists:
Destination: 0.0.0.0/0,Target: igw-xxxxxxxx. - If no such route exists, either move the RDS instance to a public subnet group, or add the IGW route (requires an IGW to be attached to the VPC).
Step 3 — Update the Security Group Inbound Rule
This is the most common misconfiguration. The default RDS security group has no inbound rules.
🔽 [Click to expand] — AWS CLI: Add inbound rule for your IP
# 1. Find your current public IP
curl -s https://checkip.amazonaws.com
# Output example: 203.0.113.45
# 2. Get the Security Group ID attached to your RDS instance
# (visible in RDS Console → Connectivity & security → VPC security groups)
# 3. Add the inbound rule (replace values accordingly)
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 3306 \
--cidr 203.0.113.45/32 \
--region us-east-1
Alternatively, via the Console: EC2 Console → Security Groups → select the group → Inbound rules → Edit inbound rules → Add rule: Type MySQL/Aurora, Source My IP.
⚠️ Never use 0.0.0.0/0 as the source for port 3306. Always restrict to your specific IP (/32 CIDR).
Step 4 — Connect from MySQL Workbench
| Workbench Field | Value |
|---|---|
| Connection Method | Standard (TCP/IP) |
| Hostname | mydb.xxxxxxxx.us-east-1.rds.amazonaws.com |
| Port | 3306 |
| Username | Your RDS master username |
| Password | Your RDS master password |
The Production-Safe Alternative: SSH Tunnel via a Bastion Host
Analogy: Think of a Bastion Host as a secure reception desk in a locked building. You authenticate at the front desk (SSH), and the receptionist escorts your request to the private office (RDS) — the office itself has no public-facing door.
For any environment beyond local dev, keep RDS in a private subnet (no IGW route) and access it through an SSH tunnel via a Bastion EC2 instance or AWS Systems Manager Session Manager.
Option A: SSH Tunnel via Bastion EC2
local port 3307"] Bastion["🖥️ Bastion EC2
Public Subnet
SSH port 22 open"] RDS["🗄️ RDS MySQL
Private Subnet
No public access"] SG_B["🛡️ Bastion SG
Allow SSH/22
from your IP"] SG_R["🛡️ RDS SG
Allow TCP/3306
from Bastion SG"] Laptop -->|"SSH Tunnel
-L 3307:rds-endpoint:3306"| Bastion Bastion -->|"Forwards to RDS
port 3306"| RDS SG_B -.->|"Guards"| Bastion SG_R -.->|"Guards"| RDS style Laptop fill:#4A90D9,color:#fff style Bastion fill:#F5A623,color:#fff style RDS fill:#9B59B6,color:#fff style SG_B fill:#D0021B,color:#fff style SG_R fill:#D0021B,color:#fff
🔽 [Click to expand] — SSH Tunnel Command
# This command forwards your local port 3307 to the RDS endpoint via the Bastion host.
# Replace all placeholder values.
ssh -N -L 3307:mydb.xxxxxxxx.us-east-1.rds.amazonaws.com:3306 \
-i /path/to/your-key.pem \
ec2-user@<BASTION_PUBLIC_IP>
# Then connect MySQL Workbench to:
# Hostname: 127.0.0.1
# Port: 3307
The Bastion EC2 instance's Security Group must allow inbound SSH (port 22) from your IP. The RDS Security Group must allow inbound TCP/3306 from the Bastion's Security Group ID (not your laptop IP).
Option B: AWS Systems Manager (SSM) Port Forwarding — No Bastion Required
This is the modern, keyless approach. It requires the SSM Agent on an EC2 instance in the same VPC, and no inbound Security Group rules are needed on that instance.
🔽 [Click to expand] — SSM Port Forwarding Command
# Prerequisites:
# 1. An EC2 instance in the same VPC with SSM Agent installed and an IAM role
# that includes the AmazonSSMManagedInstanceCore managed policy.
# 2. AWS CLI with Session Manager plugin installed locally.
aws ssm start-session \
--target i-0123456789abcdef0 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["mydb.xxxxxxxx.us-east-1.rds.amazonaws.com"],"portNumber":["3306"],"localPortNumber":["3307"]}' \
--region us-east-1
# Then connect MySQL Workbench to:
# Hostname: 127.0.0.1
# Port: 3307
Decision Guide: Which Approach Should You Use?
from local machine"]) Q1{"Is this a
production environment?"} Q2{"Do you have an
EC2 instance in the VPC?"} A1["✅ Option: Direct Public Access
Enable Publicly Accessible
Restrict SG to your IP /32"] A2["✅ Option: SSM Port Forwarding
No open ports needed
Requires SSM Agent on EC2"] A3["✅ Option: SSH Bastion Tunnel
EC2 in public subnet
RDS stays private"] A4["⚠️ Launch an EC2 instance
with SSM role, then use
SSM Port Forwarding"] Start --> Q1 Q1 -->|"No - Dev/Test"| A1 Q1 -->|"Yes - Production"| Q2 Q2 -->|"Yes"| A2 Q2 -->|"Yes, with SSH key"| A3 Q2 -->|"No"| A4 style Start fill:#4A90D9,color:#fff style A1 fill:#F5A623,color:#fff style A2 fill:#27AE60,color:#fff style A3 fill:#27AE60,color:#fff style A4 fill:#E74C3C,color:#fff
Common Errors & Root Causes
| Error / Symptom | Most Likely Root Cause | Fix |
|---|---|---|
| Connection timed out | Security Group missing inbound rule, or subnet has no IGW route | Add SG inbound rule; verify subnet route table |
| Could not resolve hostname | "Publicly Accessible" is set to No — no public DNS is assigned | Enable Publicly Accessible and apply |
| Access denied for user | Wrong username/password, or DB user lacks remote login privileges | Verify credentials; check MySQL user host binding |
| SSL connection error | MySQL Workbench enforcing SSL but certificate not configured | Download RDS CA bundle or disable SSL requirement for dev |
IAM & Security Checklist
- ✅ Restrict Security Group inbound rule to
<your-ip>/32, never0.0.0.0/0for port 3306. - ✅ For production, keep RDS in a private subnet — use SSM or Bastion tunnel.
- ✅ Enable RDS encryption at rest (KMS) and in-transit SSL/TLS.
- ✅ Use IAM database authentication instead of static passwords where possible.
- ✅ Rotate the RDS master password using AWS Secrets Manager.
- ✅ Enable VPC Flow Logs to audit connection attempts to your RDS subnet.
Glossary
| Term | Definition |
|---|---|
| Publicly Accessible | An RDS instance attribute that, when enabled, causes AWS to assign a public DNS hostname and IP to the instance, making it reachable from outside the VPC. |
| Security Group | A stateful virtual firewall operating at the resource level within a VPC, controlling inbound and outbound traffic via allow-only rules. |
| Internet Gateway (IGW) | A horizontally scaled, redundant VPC component that enables communication between resources in a VPC and the internet. |
| Bastion Host | A hardened EC2 instance in a public subnet used as a secure jump server to access resources in private subnets. |
| SSM Session Manager | An AWS Systems Manager capability that provides secure, auditable shell and port-forwarding access to EC2 instances without requiring open inbound ports or SSH keys. |
Next Steps
- 📖 Official Docs: Working with a DB instance in a VPC
- 📖 AWS Systems Manager Session Manager
- 📖 IAM Database Authentication for RDS
Comments
Post a Comment