9 min read

When Not to Migrate from MySQL to PostgreSQL

I run PostgreSQL for a living and I still tell some teams to stay on MySQL. Here are the cases where migrating is the wrong call, and a decision framework that beats database dogma.

I am a PostgreSQL practitioner. I build tooling for it, I run it in production, and given a greenfield project I will pick it almost every time. Which is exactly why I want to write down the cases where I have told teams not to migrate off MySQL, because the advice you should trust is the advice that costs the person giving it something.

The migration pitch is easy to make. PostgreSQL has richer SQL, a deep extension ecosystem, transactional DDL, better JSON indexing, and momentum. All true. What the pitch leaves out is that a database migration is one of the highest-risk projects an engineering organization can run: months of dual-running, subtle behavioral differences surfacing in production, and a long stretch where the team is expert in the system they are leaving and novice in the one they are entering.

MySQL 8.x is a good database. InnoDB is a genuinely excellent storage engine. If your system is working, the burden of proof is on the migration, not on the status quo. Here are the situations where I think that burden is not met.

Your team's MySQL depth is an asset with a price tag

An operator who has run InnoDB for eight years knows things no document captures: how this workload behaves during a purge lag incident, which ALTER TABLE variants are safe at 2 a.m., what Threads_running looks like ten minutes before trouble. Migrate, and that depth resets to near zero. The vacuum mindset, the process-per-connection model, the planner's behavior without hints, the wraparound story: all of it must be learned, usually the hard way, usually during incidents.

I have watched a team with excellent MySQL instincts spend their first PostgreSQL year rediscovering operational maturity they already had. The engineering time was budgeted; the confidence loss was not. If your MySQL operators are strong and your PostgreSQL bench is thin, that gap is a real cost. It is payable, but it belongs in the decision explicitly, not as a footnote.

The ecosystem argument cuts both ways

PostgreSQL's extension ecosystem is a legitimate advantage, but MySQL's operational ecosystem is quietly superb at specific jobs. Online schema change via gh-ost or pt-online-schema-change is a solved, battle-hardened problem. ProxySQL is a mature traffic layer. Orchestrator handles replication topology management. Vitess offers horizontal sharding with years of production mileage at enormous scale. Percona Toolkit covers the long tail of operational chores.

PostgreSQL has answers in each category, and some are excellent, but if your architecture leans hard on one of these tools, verify the replacement story before you commit. A team sharding MySQL with Vitess, for example, should treat the migration as a re-architecture, not a port. The honest comparison work belongs up front; our comparison pages exist because these tradeoffs deserve specifics rather than slogans.

Simple CRUD at scale is a MySQL sweet spot

Strip away the feature checklists and ask what your workload actually does. If the answer is primary-key lookups, short indexed range scans, and single-row writes at high concurrency, you are describing the workload InnoDB was refined for over two decades. Its clustered primary key organization means a PK lookup lands directly on the row data, and its undo-log MVCC keeps update-heavy tables compact without a vacuum cycle.

PostgreSQL handles this workload well too, but it does not handle it so much better that a migration pays for itself. The gains that justify migrations come from the features the workload can use. A quick way to ground this conversation is to inventory what your application actually asks of MySQL:

SELECT routine_type, COUNT(*) AS objects
FROM information_schema.routines
WHERE routine_schema NOT IN ('sys', 'mysql',
                             'information_schema', 'performance_schema')
GROUP BY routine_type;

Run similar inventories for triggers, views, and column types, then look at the query patterns in performance_schema. If the workload would light up on PostgreSQL, it usually looks like this kind of query being awkward or impossible today: expression indexes over JSON documents, partial indexes for sparse predicates, window-heavy analytics inside the OLTP store.

CREATE INDEX orders_pending_idx
    ON orders (customer_id, created_at)
    WHERE status = 'pending';

SELECT customer_id,
       created_at,
       rank() OVER (PARTITION BY customer_id
                    ORDER BY created_at DESC) AS recency_rank
FROM orders
WHERE status = 'pending';

If nothing in your backlog resembles that, and your MySQL boxes are bored, the honest conclusion is that migration buys you a different logo and a year of risk.

Existing HA investment is expensive to rebuild

High availability is where migration costs hide. A MySQL shop with mature semi-synchronous replication, orchestrator-driven failover, tested runbooks, and years of failover drills has bought something expensive: justified confidence. PostgreSQL's equivalent stack, typically Patroni with etcd or a managed offering's HA tier, is solid, but your instance of it starts at zero mileage. Failover behavior, split-brain protection, connection routing, backup and PITR procedures: each must be rebuilt and re-drilled.

The same goes for the surrounding muscle memory. Backup verification jobs, restore time objectives you have actually measured, capacity models tuned to InnoDB's behavior. None of it transfers. If your HA posture is the best thing about your current platform, weigh what it costs to reach the same posture on the new one.

Managed cloud offerings soften this argument without eliminating it. A managed PostgreSQL HA tier hands you failover machinery on day one, but it does not hand you the drills, the application-side retry behavior you have validated against real failovers, or the confidence that your alerting catches the failure modes that matter. If you migrate, schedule game days on the new platform early and treat the first year's HA posture as unproven until it has been exercised on purpose, not just described in a console.

A decision framework instead of dogma

Here is the framework I actually use, as four questions in order. First, is there a concrete feature pull? Name the queries, workloads, or extensions that PostgreSQL enables and MySQL blocks. "Better JSON" is not an answer; a specific access pattern with a specific index strategy is. Second, what is the team gradient? Count the engineers who have operated each system in production through an incident. If the MySQL column is much larger, price in a year of reduced operational confidence. Third, what breaks in the ecosystem? List every tool in the critical path, from schema change to failover to backups, and confirm each has a replacement you have tested, not just identified. Fourth, what is the migration's opportunity cost? The engineers running the dual-write phase are not building product.

If question one produces a strong answer and questions two through four produce manageable ones, migrate, and do it deliberately. If question one is weak, stop there. A migration justified only by preference fails in the middle, which is the most expensive place to fail. And if the pull is real but the timing is wrong, a legitimate answer is "not yet": adopt PostgreSQL for the next new service, build team depth on lower-stakes systems, and revisit the core migration in a year. Our overview of PostgreSQL itself lays out what the feature pull genuinely looks like when it exists.

How MonPG fits, if and when you do land on PostgreSQL

MonPG is a PostgreSQL-only monitoring product, so I have an obvious interest in your migration, and everything above still says: only migrate for real reasons. When those reasons exist and the cutover happens, the first months are precisely when operational blindness is most dangerous, because the team's instincts still speak MySQL. That is the window where PostgreSQL monitoring with MonPG earns its keep: query history from pg_stat_statements, lock chains, vacuum and bloat signals, and replication lag collected from day one, so the new platform builds a baseline while the team builds intuition.

MonPG will not monitor the MySQL side of a dual-running setup; keep your existing tooling there until the old system is retired. And if you read this piece and concluded that staying on MySQL is right for you, that is a good outcome too. The goal is a database decision made with clear eyes, because those are the decisions that hold up under load.