Learning resources
David Sterling  

How to Migrate PostgreSQL to Amazon RDS

If your Houston startup or enterprise is still running PostgreSQL on a self-managed server, Amazon RDS is one of the fastest ways to cut operational overhead. AWS handles backups, patching, failover, and storage scaling, and its managed engine keeps you on supported versions — AWS publishes guidance on when new open source engine versions land on RDS and Aurora so you can plan upgrades instead of reacting to them.

In this tutorial, you’ll migrate an on-premises PostgreSQL database to RDS using pg_dump and pg_restore. This approach works well for databases up to a few hundred GB where you can schedule an hour or two of downtime. If you need a zero-downtime move or continuous sync, plan on logical replication instead — the dump-and-restore flow here is still the right way to seed the target first.

Before You Start

Gather four things:

  1. Source PostgreSQL version — run SELECT version(); and confirm it’s on the supported versions list for RDS.
  2. Installed extensionsSELECT name FROM pg_available_extensions WHERE installed_version IS NOT NULL; and verify each one exists on RDS before you start. Extensions like postgis and pgcrypto are available; a few less common ones are not.
  3. Database sizeSELECT pg_size_pretty(sum(pg_database_size(datname))) FROM pg_database; so you can size the RDS storage correctly and estimate how long the restore will take.
  4. Connection settings — host, port, and SSL mode from your application configuration, plus the list of every client that connects (apps, cron jobs, BI tools).

Step 1: Create the RDS Instance

You can use the console, but the AWS CLI is reproducible and scriptable. Create the instance with automated backups and Multi-AZ from day one:

aws rds create-db-instance \
  --db-instance-identifier appdb-prod \
  --engine postgres \
  --engine-version 16.8 \
  --db-instance-class db.t4g.large \
  --allocated-storage 100 \
  --master-username postgres \
  --master-user-password 'CHANGE_ME' \
  --backup-retention-period 7 \
  --multi-az \
  --publicly-accessible false

Wait until the instance is ready: aws rds describe-db-instances --db-instance-identifier appdb-prod --query 'DBInstances[0].DBInstanceStatus' should return available. Provisioning usually takes 10-15 minutes.

Step 2: Dump the Source Database

First do a schema-only dry run. It’s fast and it catches incompatibilities (missing extensions, unsupported types) before you commit to a full data dump. Review schema.sql for anything that won’t translate to RDS, then take the real dump. Use the custom format (-Fc): it compresses the output and lets pg_restore restore tables in parallel:

pg_dump -h source-db.example.com -U app_user --schema-only -d appdb -f schema.sql
pg_dump -h source-db.example.com -U app_user -Fc -d appdb -f appdb.dump

Step 3: Restore to RDS

Restore with --no-owner — RDS manages superuser roles for you, so object ownership must be remapped to the RDS master user. Use --jobs to parallelize the data load:

pg_restore -h appdb-prod.xxxxx.us-east-1.rds.amazonaws.com \
  -U postgres -d appdb --no-owner --jobs 4 appdb.dump

If you used custom roles beyond the default, recreate them on RDS first (or pass --no-privileges). The AWS guide on importing data into PostgreSQL on RDS covers the edge cases. Check the exit code and review any warnings before you call it done.

Step 4: Validate the Migration

Compare row counts before and after. A quick spot-check across the largest tables:

SELECT schemaname, relname, n_live_tup
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC LIMIT 10;

Then run a few real queries your application uses and compare response times. Don’t trust n_live_tup blindly — it’s an estimate until statistics are refreshed. For critical tables, do an exact SELECT count(*) on both sides.

Step 5: Cut Over

  1. Update the application connection string to point at the RDS endpoint. Prefer a DNS alias such as db.internal.example.com so future failovers don’t require code changes.
  2. Enable SSL in the connection (sslmode=require or verify-full). RDS certificates are free and the default endpoint supports TLS.
  3. If you use a connection pooler like PgBouncer, update its config first, then restart it before pointing apps at it.
  4. Schedule the cutover during a maintenance window, not peak traffic.
  5. Keep the old server available read-only for one week as a rollback path.

Step 6: Post-Migration Checklist

  • Run ANALYZE; so the planner has fresh statistics.
  • Confirm automated backups are enabled (set in Step 1) and test a restore.
  • Set CloudWatch alarms on CPU, free storage, and connection count.
  • Recreate scheduled jobs — pg_cron on RDS requires the extension plus separate configuration.
  • Retire the old server only after the rollback window closes.

Next Steps

For the full walkthrough, see the AWS documentation on working with PostgreSQL on Amazon RDS. Moving to Aurora instead? The dump-and-restore flow is nearly identical, but review Aurora’s cluster model and reader endpoints before you commit.

Leave A Comment