DEV Community

Aryamaan jain
Aryamaan jain

Posted on • Originally published at striker-aryu56.Medium on

How We Upgraded PostgreSQL on AWS RDS in Production

Upgrading PostgreSQL on AWS RDS
Guide to Upgrading PostgreSQL on AWS RDS for Production Environments

At one of my previous organizations, we were still running a PostgreSQL 12.x version on AWS RDS. This database powered our Metabase instance , which was critical for analytics across the org. The catch? Since PostgreSQL 12 had already gone out of mainstream support, we had to rely on extended support  — and pay extra for it.

Naturally, this sparked conversations about cost savings and long-term sustainability. The decision was clear: we needed to upgrade PostgreSQL to a supported version, for us it was PostgreSQL 17.

But like any database upgrade, it wasn’t just about clicking an “Upgrade” button. It meant understanding compatibility, preparing for edge cases, and making sure we didn’t bring down production dashboards that half the company relied on.

That’s when I started drafting a structured upgrade plan  — something I wish I had when we first went through it.

The Upgrade Journey: Steps I Followed

Step 1: Change Log

First, I dug into PostgreSQL’s release notes. This was important to identify deprecated features or breaking changes that could cause Metabase queries to fail.

Step 2: Compatible Target Version

AWS doesn’t allow skipping major versions, so I had to check the valid upgrade paths from 12.x using the AWS CLI. Luckily, for us, it was a straightforward single-step upgrade.

aws rds describe-db-engine-versions \
  --engine postgres \
  --engine-version 12 \
  --query "DBEngineVersions[*].ValidUpgradeTarget[*].{EngineVersion:EngineVersion}" \
  --output text
Enter fullscreen mode Exit fullscreen mode

📖 Reference: AWS RDS Upgrade Targets

Eg. Target Versions
Eg. Target Versions

Step 3: Instance class compatibility

Not every instance type supports all PostgreSQL versions, so I had to cross-check our RDS class against AWS’s documentation. In our case, we were on db.m6i.large, which turned out to support PostgreSQL 17 perfectly for our needs.

📖 Reference: AWS RDS Instance Class

AWS RDS Instance Class

Step 4: Parameter group

PostgreSQL upgrades can introduce new parameters or remove existing ones, which may impact your setup. To be safe, I created a new parameter group for the target version and reviewed it. Since we hadn’t customized much, the defaults worked fine.

Step 5: Database Content

Clean up potential blockers before upgrading:

Prepared transactions:

SELECT count(*) FROM pg_catalog.pg_prepared_xacts;
Enter fullscreen mode Exit fullscreen mode

Replication slots:

SELECT * FROM pg_replication_slots;
Enter fullscreen mode Exit fullscreen mode

reg* data types:

SELECT count(*) FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n, pg_catalog.pg_attribute a
  WHERE c.oid = a.attrelid
     AND NOT a.attisdropped
     AND a.atttypid IN ('pg_catalog.regproc'::pg_catalog.regtype,
                         'pg_catalog.regprocedure'::pg_catalog.regtype,
                         'pg_catalog.regoper'::pg_catalog.regtype,
                         'pg_catalog.regoperator'::pg_catalog.regtype,
                         'pg_catalog.regconfig'::pg_catalog.regtype,
                         'pg_catalog.regdictionary'::pg_catalog.regtype)
     AND c.relnamespace = n.oid
     AND n.nspname NOT IN ('pg_catalog', 'information_schema');
Enter fullscreen mode Exit fullscreen mode

Invalid databases:

SELECT datname FROM pg_database WHERE datconnlimit = -2;
Enter fullscreen mode Exit fullscreen mode

Unknown data types:

SELECT DISTINCT data_type FROM information_schema.columns 
WHERE data_type ILIKE 'unknown';
Enter fullscreen mode Exit fullscreen mode

📖 Reference: Official Postgres Upgrade Docs

Step 6: Extension Compatibility

Extensions (like uuid-ossp, pgcrypto, etc.) are not automatically upgraded during a major version upgrade. So I listed all installed extensions and verified their compatibility with the new version.

SELECT * 
FROM pg_extension pe
JOIN pg_available_extension_versions pev 
  ON pev.name = pe.extname;
Enter fullscreen mode Exit fullscreen mode

Verify compatibility in AWS Postgres Extensions Release Note

Step 7: Pending maintenance

Checked RDS console for any pending maintenance tasks — these can conflict with upgrades, as running them during the upgrade can cause issues. You can view pending maintenance in the AWS RDS console under your DB instance’s “Maintenance & backups” section.

Step 8: Take snapshot

Took a manual snapshot before starting. It serves as a fallback in case the upgrade fails or anything goes wrong.

Step 9: Check Application Compatibility

Finally, I tested Metabase itself with the upgraded PostgreSQL version in staging. This step was crucial because Metabase Docker images often lock supported PostgreSQL versions. That’s when we ran into a new issue: our current Metabase version didn’t support PostgreSQL 17. This meant we had to upgrade Metabase as well. I created a forked Docker image with a few of our custom patches, then tested it against the new database to ensure everything worked smoothly.

Final Checklist

- [] Change log
- [] Compatible Target version
- [] Instance class compatibility
- [] Parameter group
- [] Database Content
- [] Extension compatibility
- [] Pending maintenance
- [] Take snapshot
- [] Application compatibility with new postgres version
Enter fullscreen mode Exit fullscreen mode

Other Points to Consider

  • Blue-Green Deployment: We used a blue-green deployment approach to test the upgrade on a separate environment, which allowed for a smooth transition to production.
  • Performance Monitoring: Throughout the upgrade process, we monitored the RDS database diligently to ensure everything was working smoothly. We kept an eye on CPU, memory, disk usage, and query performance both before and after the upgrade to catch any regressions early.
  • Driver & Connection Compatibility: We made sure that all applications were using PostgreSQL drivers compatible with the new version to avoid connection issues.
  • Security Review: We reviewed roles, permissions, and SSL settings to ensure security wasn’t impacted.
  • Communicate Downtime: I announced the upgrade downtime for Metabase and scheduled it at night, when traffic was minimal, to reduce disruption for users.

For us, the upgrade was about more than just security or new features  — it was about avoiding unnecessary costs while ensuring reliability. What started as a cost-saving initiative turned into a lesson on systematic upgrades and resilience planning.

If you’re in a similar boat with aging PostgreSQL versions on RDS, hopefully, this step-by-step narrative gives you a practical starting point.

Refs:

202509230243

Top comments (0)