Securely Accessing Private RDS Databases Using SSH Tunneling and a Bastion Host

I’ve been using AWS services like EC2 and RDS under the free tier and recently started incurring charges due to the use of public IP addresses. AWS provides one free public IP, but my RDS instance had another public IP attached — and that’s where the billing began.
AWS billing showing charges for additional public IPv4 addresses.
A better, more secure, and cost-effective solution is to keep your RDS private within a VPC and connect to it via a method called SSH tunneling through a bastion host.
Below, I’ll explain what that means and how you can set it up.
🔁 What is SSH Tunneling?⌗
SSH tunneling (port forwarding) is a method of transporting network data over an encrypted SSH connection. SSH is a standard protocol for secure remote logins and file transfers over untrusted networks.
It also provides a way to secure data for any given application using port forwarding — the data flows through an encrypted SSH connection, making it safe from interception. This is especially useful when you need to connect to a private network (one without a public IP) via a bastion host, such as in production or secure VPC environments.
🧱 What is a Bastion Host?⌗
A bastion host is a public-facing machine that acts as a gateway between your local computer and private infrastructure. It allows you to connect securely to private resources without exposing them directly to the internet.
In our case, an EC2 instance serves as the bastion host that connects to an RDS instance located in a private subnet.
🛠️ Example Setup⌗
Let’s say we have the following:
Secure access to a private RDS through a Bastion Host using SSH tunneling.
Component | Example |
---|---|
Bastion Host (EC2) | 3.25.100.100 (public IP) |
RDS Endpoint | mydb.databsexxx.rds.amazonaws.com (private) |
RDS Port | 3306 |
Local Port | 3307 |
SSH Key | key.pem |
User | ec2-user |
💡 Note: The EC2 instance must be allowed to connect to the RDS instance. In your RDS setup, make sure the EC2’s security group is authorized for inbound access.
🔐 SSH Command⌗
ssh -i /path/to/key.pem -L 3307:mydb.databsexxx.rds.amazonaws.com:3306 ec2-user@3.25.100.100
This command does the following:
- Connects to the bastion EC2 instance
- Forwards your local port
3307
to the RDS instance’s port3306
- Allows your local database client to communicate with the private RDS as if it were running locally
💻 Connect from a Database Client⌗
Once the SSH tunnel is active, open your preferred database client (like MySQL Workbench, DBeaver, or Beekeeper Studio) and use:
Host: 127.0.0.1
Port: 3307
Username/Password: Your RDS credentials
Database Name: <your_db_name>
That’s it! You’re now securely connected to a private RDS instance.
🎯 Benefits⌗
- No need to expose RDS publicly (better security)
- Avoids unnecessary billing for Elastic IPs
- Follows DevOps best practices for accessing private cloud resources
📌 Bonus Tip: Simplify with SSH Config⌗
You can avoid typing the full SSH command every time by adding this to your ~/.ssh/config
file:
Host my-bastion
HostName 3.25.100.100
User ec2-user
IdentityFile ~/path/to/key.pem
LocalForward 3307 mydb.databsexxx.rds.amazonaws.com:3306
Then just run:
ssh my-bastion
🔚 Conclusion⌗
If you want to make your infrastrucure more secure and decrease the cost, the should keep your database with a private subnet and attach it to the ec2 instance. To connect to sql clients you can use a bastion host and SSH tunneling to access your database securely