Postgres vs MySQL: The Whiteboard Version, Not the Flame War
Where Postgres genuinely pulls ahead, where MySQL holds real ground, the differences everyone overweights, and a decision procedure whose top factor is organizational, not technical.
"Postgres or MySQL?" is the tabs-vs-spaces of backend engineering, except the answer actually matters and most of the discourse is a decade stale. I run both in production — MySQL underneath this very site's stack, Postgres under several client systems — and the honest modern answer is: both are excellent, the differences are real but narrower than the flame wars claim, and the deciding factors are rarely the ones people argue about. Here's the comparison as I'd give it across a whiteboard, not a comment section.
Where Postgres genuinely pulls ahead
- The type system and extensibility. Arrays, ranges, real enums, composite types, and
jsonbwith proper GIN indexing — Postgres lets relational and document styles cohabit honestly. Then the extension ecosystem multiplies it: PostGIS (the undisputed geospatial king),pg_trgmfor fuzzy search,pgvectorfor embeddings — capabilities that in MySQL-land mean adding another database to your stack. This is Postgres's deepest moat: it absorbs adjacent workloads (decent search, queues, vectors) that would otherwise be infrastructure. - DDL inside transactions. Migrations that either fully apply or fully roll back. MySQL's implicit-commit DDL means a failed multi-step migration leaves you somewhere in between — a property you learn to fear during zero-downtime schema work.
- Sophisticated query machinery. Richer join strategies (hash/merge joins as first-class citizens), partial and expression indexes, and a planner that handles analytical-ish queries over normalized schemas with more grace. Complex reporting on Postgres simply requires fewer workarounds.
- Stricter defaults. Postgres rejects nonsense loudly; historical MySQL coerced and truncated silently. Modern MySQL's strict mode closes most of the gap — but Postgres never had the gap.
Where MySQL holds real ground
- Replication ergonomics and ecosystem maturity. MySQL's replication has been the workhorse of read-scaled web platforms for twenty years; the tooling around it (orchestrators, proxies, failover automation, and battle-tested patterns at Facebook/Shopify/GitHub scale) is deep and boring in the best way. Postgres replication is fully capable now, but the MySQL playbook is thicker.
- The connection model. MySQL connections are cheap threads; Postgres connections are processes, and a swarm of app servers exhausts them fast — meaning PgBouncer is effectively mandatory kit for Postgres at scale, an extra component MySQL deployments simply don't need. (Serverless/Lambda architectures feel this hardest.)
- Clustered primary keys. InnoDB stores rows physically ordered by primary key — ranges over the PK (the classic "recent rows for this tenant" pattern) read beautifully sequentially. Postgres heap tables + secondary indexes get the same result with covering indexes, but InnoDB gives it to you by default.
- Operational familiarity where it counts: your team. A team with a decade of MySQL scar tissue operates MySQL better than Postgres, full stop — and databases fail operationally far more often than they fail featurely.
The differences people overweight
Raw single-node benchmark performance: for typical OLTP web workloads, both are so fast that your ORM habits and caching layer dominate before engine choice does. JSON support: Postgres's jsonb is better, but MySQL's JSON functions cover the common cases fine. "MySQL loses data": a 2008 meme about MyISAM; InnoDB with sane settings has been durably boring for fifteen years. Licensing anxiety about Oracle: real enough to note (MariaDB exists as the escape hatch), rarely decisive.
The actual decision procedure
1. Team runs one of them well already? → That one. Seriously. (80% of cases end here.)
2. Geospatial, vectors, fuzzy search, or
rich-typed domain modeling on the roadmap? → Postgres (extensions are the moat)
3. Massive read-replica web scale with
established MySQL ops tooling? → MySQL keeps earning its seat
4. Greenfield, no constraints from 1–3? → Postgres, by a modest margin —
the defaults are stricter, DDL is
transactional, the ceiling is higher
5. Whichever you pick → managed hosting unless ops IS your
product, connection pooling from day
one (mandatory for PG), backups you
have actually restored
Notice the shape of that list: the top factor is organizational, not technical. Both engines will scale further than your product's next three years; neither will save a schema with no index discipline or an app that treats transactions as decoration. Pick with the checklist, commit without angst, and spend the reclaimed argument-hours on the things that actually take databases down — which, in my incident history, have been migrations, connection storms and forgotten WHERE clauses, in that order, on both engines, forever.
Mid-decision on a real system — or contemplating a migration between the two? The second one especially deserves an hour of adult supervision; I've done it in both directions and only one of them was fun.