Oct 30, 20265 min read

How to Connect to a Private RDS Database From Your Laptop

Four ways to reach an RDS PostgreSQL instance in private subnets from your machine: SSM port forwarding, a bastion with an SSH tunnel, AWS Client VPN, and an access proxy that comes with the database.

Putting RDS in private subnets is the right default, and it immediately raises the next question: how do you run a query from your laptop? psql cannot reach a private IP in a VPC, and making the database publicly accessible to get around that undoes the reason it was private in the first place.

Every working answer puts something inside the VPC that forwards your connection. This guide covers the four common ones, starting with Encore, where database access is a CLI command because the access path is created with the database.

Private RDS access options at a glance

EncoreSSM port forwardingBastion and SSH tunnelAWS Client VPN
Extra infrastructureNone, created with the environmentAn EC2 instance with the SSM agentA public EC2 instanceA VPN endpoint and certificates
Something to patchNothing you runThe forwarding instanceThe bastionVPN endpoint config and clients
CredentialsYour Encore login, read-only by defaultIAM plus a database passwordSSH key plus a database passwordVPN certificate plus a database password
Commandencore db shell orders --env=prodaws ssm start-session ...ssh -L ...VPN client, then psql
CostIncludedThe forwarding instanceThe bastion instancePer endpoint association and connection hour

Each option is covered below, starting with Encore.

Accessing the database from the CLI with Encore

Encore combines an open source infrastructure SDK for TypeScript and Go with a platform that provisions and deploys into your own AWS or GCP account. Databases are declared in code, and on AWS Encore places RDS in private storage subnets that accept connections only from the compute subnets. The platform runs migrations through Emissary, a SOCKS proxy in your environment, so the database never needs a public endpoint, and the CLI gives your team access without one either.

Application code passes through Encore and infrastructure guardrails to resources provisioned in your own AWS or GCP account.
Encore provisions the infrastructure your application needs in your own AWS or GCP account.

The database is declared where it is used:

// orders/db.ts import { SQLDatabase } from "encore.dev/storage/sqldb"; // RDS on AWS in a private subnet, a local Postgres under encore run. export const db = new SQLDatabase("orders", { migrations: "./migrations" });
Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

And reached by name from your laptop:

~/shop
# psql against the orders database in the prod environment, read-only by default$ encore db shell orders --env=prod # Write access when you need it, for a one-off fix$ encore db shell orders --env=prod --write # A local port for TablePlus, DBeaver or a script$ encore db proxy --env=prod --port 5433

encore db shell defaults to read-only permissions, and --write, --admin and --superuser raise them explicitly, so a quick look at production data does not run with the master password. encore db conn-uri orders --env=prod prints a temporary connection string for tools that want one.

The same commands without --env connect to the local Postgres that encore run starts.

Option 1: SSM Session Manager port forwarding

Session Manager can forward a local port to a host the instance can reach, with no inbound ports open. You need an EC2 instance in the VPC with the SSM agent and an instance profile for Systems Manager, a security group rule allowing it to reach the database on 5432, and the Session Manager plugin for the AWS CLI on your laptop:

aws ssm start-session \ --target i-0123456789abcdef0 \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters '{"host":["orders.abc123.eu-west-1.rds.amazonaws.com"],"portNumber":["5432"],"localPortNumber":["5433"]}' # In another terminal psql "host=localhost port=5433 dbname=orders user=app sslmode=require"

Access is controlled with IAM and every session is logged, which makes this the usual choice on AWS today. You still keep the forwarding instance running and patched, and you still need a database user and password for psql.

Option 2: a bastion host and an SSH tunnel

The classic approach is a small EC2 instance in a public subnet that you SSH into, forwarding a local port to the database:

ssh -N -L 5433:orders.abc123.eu-west-1.rds.amazonaws.com:5432 ec2-user@bastion.example.com

It works with any SQL client that supports SSH tunnels. The costs are an instance exposed on port 22, SSH keys to distribute and revoke when people leave, and a host that needs patching. SSM port forwarding, below, avoids the open port.

Option 3: AWS Client VPN

AWS Client VPN puts your laptop on the VPC network, so psql connects to the RDS endpoint directly. It suits teams that need access to many private resources, not just one database, and it can authenticate users with Active Directory, SAML or mutual certificates.

It is also the most setup: a Client VPN endpoint, certificates in ACM, subnet associations, authorization rules and a VPN client on every laptop. It is billed per endpoint association hour and per connection hour, which adds up for a single database.

Good to know

Whichever path you use, connect with a role that matches the task. Running ad-hoc queries as the master user is how accidental UPDATE statements without a WHERE clause reach production. Create a read-only Postgres role for browsing and keep write access deliberate.

How to choose

Pick Encore when you want private databases in your own AWS account with team access through the CLI, read-only by default.

Pick SSM port forwarding for occasional access to an RDS instance you already run, a bastion with an SSH tunnel only if your tools or policies require SSH, and Client VPN when people need network access to many private resources at once.

Frequently asked questions

How do I connect to an RDS instance in a private subnet?

You need something inside the VPC to forward the connection. The common options are SSM Session Manager port forwarding through an EC2 instance, an SSH tunnel through a bastion host, or AWS Client VPN. Each makes the database reachable on a local port, where psql or a GUI client can connect to it.

Should I make my RDS instance publicly accessible to connect from my laptop?

No. A publicly accessible instance with a security group open to your IP works, but it exposes the database endpoint to the internet, depends on your IP not changing, and is easy to leave open. Port forwarding or a VPN keeps the database private.

Is there a way to open a database shell on a private RDS without a bastion?

With Encore, yes. Run encore db shell <database> --env=<environment> to open psql against the database in that environment, read-only by default, or encore db proxy --env=<environment> to expose it on a local port for GUI tools. The database itself stays in private subnets with no public endpoint.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders