By Ryan Calloway. Updated May 2026.
“PostgreSQL or MySQL” is the most-asked database question on r/webdev for the third year running, and the answer that gets upvoted has not changed: PostgreSQL for greenfield projects unless you can name a specific reason to pick MySQL. The Stack Overflow 2025 Developer Survey backs the trend — PostgreSQL at 55.6% adoption among professional developers (up from 48.7% in 2024), MySQL at 40.5%, PostgreSQL “most admired” four years in a row at 65%. The more honest read lives in the recurring r/Database thread “PostgreSQL vs MySQL for a new project”, where six concrete cases still tip toward MySQL: PlanetScale and Vitess hosts, hosted CMS like WordPress, an existing team that runs MySQL, simple read-heavy workloads, multi-primary clusters, and tight binlog-driven CDC pipelines. Six questions decide everything else. This is that side-by-side.
Verdict at a glance
- Best for: PostgreSQL 18 for new web apps —
jsonb, partial indexes, pgvector, transactional DDL, virtual generated columns by default since September 25, 2025. - Not best for: PostgreSQL on PlanetScale, in a WordPress stack, or where your ops team already runs MySQL fleets at scale.
- Watch out for: Postgres connection-pool footguns at scale (use PgBouncer or pgcat); MySQL JSON indexing requires generated columns; default isolation differs (PG: READ COMMITTED, MySQL: REPEATABLE READ).
- Use MySQL 8.4 LTS for: read-heavy simple-CRUD workloads, hosted MySQL platforms (PlanetScale, Vitess), and teams with deep MySQL operational muscle memory.
Quick answer
PostgreSQL 18 by default for new web apps. jsonb with GIN indexes, generated columns, partial indexes, transactional DDL, and the catalog of extensions (PostGIS, pgvector, TimescaleDB) make it the safer long-term pick. Choose MySQL 8.4 LTS (or 9.x innovation) if you are deploying on a managed MySQL platform, your workload is read-heavy and write-light with simple queries, or your team already runs it cold. The six questions below tell you which bucket you are in; the schema-level differences explain why.
The short comparison
| Concern | PostgreSQL 18 | MySQL 8.4 LTS / 9.x |
|---|---|---|
| Latest stable | 18 (released September 25, 2025) | 8.4 LTS (April 2024); 9.x innovation |
| Storage engine | One engine (heap), MVCC built in | InnoDB |
| JSON | jsonb with GIN, full operator set |
JSON column; index via generated columns |
| Indexing | B-tree, Hash, GIN, GiST, BRIN, partial, expression, B-tree skip scan | B-tree, Hash, full-text, spatial |
| Generated columns | Stored and virtual; virtual is the default in PG 18 | Stored (indexable) and virtual (not indexable) |
| Vector search | pgvector (de-facto standard, HNSW + IVFFlat) | VECTOR type in 9.x; HeatWave for managed |
| Transactional DDL | Full (BEGIN; ALTER TABLE; COMMIT) | Single-statement atomic DDL since 8.0 |
| Replication | Streaming (WAL), logical (Pub/Sub) | Logical (binlog), semi-sync, group replication |
| Default isolation | READ COMMITTED | REPEATABLE READ |
| Stack Overflow 2025 use | 55.6% | 40.5% |
Six of those tilt toward PostgreSQL on a new project. The other four are roughly even, or tilt toward MySQL in narrow cases. The Bytebase team, who operate both at scale on Google Cloud SQL, summarise the picture in their 2026 PostgreSQL vs MySQL comparison: “for most workloads, performance is comparable within 30%; missing an index causes 10x to 1000x degradation regardless of which engine you chose.”
6 questions that decide it
1. How much of your data is JSON or semi-structured?
If user preferences, webhook payloads, audit logs, feature flags, or LLM tool responses are more than ~5% of your storage, this question alone settles the call. PostgreSQL’s jsonb stores binary JSON, supports indexing on individual keys with GIN, and exposes a rich operator set:
CREATE TABLE events (
id bigserial PRIMARY KEY,
payload jsonb NOT NULL
);
CREATE INDEX idx_events_payload ON events USING GIN (payload);
SELECT id FROM events
WHERE payload @> '{"type": "checkout", "country": "DE"}'
ORDER BY id DESC LIMIT 50;
One GIN index covers any key without changing the schema. MySQL’s JSON column type works, but you index it through generated columns:
CREATE TABLE events (
id bigint AUTO_INCREMENT PRIMARY KEY,
payload JSON NOT NULL,
payload_type VARCHAR(50) AS (payload->>'$.type') STORED,
INDEX idx_payload_type (payload_type)
);
It works. It is more verbose. You have to predict every key you might filter on. PostgreSQL’s GIN handles arbitrary access patterns with one index.
2. Do you need vector search?
RAG, semantic search, recommendation systems, LLM memory — pgvector is the standard answer in 2026. Install the pgvector extension, add a vector(1536) column, query with <=> for cosine distance. HNSW and IVFFlat indexes are mature. MySQL 9.x added a native VECTOR type with up to 16,383 dimensions, but indexing is still narrower; serious AI workloads on MySQL usually go through Oracle HeatWave, which is the enterprise managed offering.
3. How write-heavy and concurrent is your OLTP load?
This is the question where MySQL still has a real edge. Uber’s well-known “Why we switched from Postgres to MySQL” post is still the canonical case: under extreme write-amplification at fleet scale, PostgreSQL’s per-process connection model and MVCC bloat became operational pain. The OtterTune analysis walks through the same trade-offs (XID wraparound risk, autovacuum tuning) without the conclusion that you should migrate. For most web apps under, say, 5,000 writes per second, both are fine. Above that, MySQL’s InnoDB rollback segment is leaner than PostgreSQL’s heap MVCC if you are not careful with vacuum.
4. What does your replication and HA story look like?
PostgreSQL streaming replication via WAL is rock-solid for hot standbys. Logical replication (built in since PG 10) handles “replicate one schema to a different database” cleanly. PostgreSQL 18 added native uuidv7() for timestamp-ordered UUIDs that index well; see the PostgreSQL 18 release announcement (September 25, 2025) for the full feature list.
MySQL’s group replication is the more mature multi-primary story. If you need active-active writes across three nodes without a cluster manager bolted on, MySQL is the better-trodden path. PostgreSQL has BDR (commercial via EDB) and a few extensions, but the BSD-licensed core does not ship multi-primary. CDC pipelines also tilt slightly to MySQL: Debezium and similar consumers were binlog-native before they were WAL-native, and the binlog format remains less version-sensitive in production.
5. What’s your hosting and platform constraint?
This question often pre-decides the answer. Specialist hosts skew PostgreSQL: Neon’s Git-style branching for staging, Supabase’s full backend on PG, Crunchy Bridge’s operational chops. The best managed MySQL experience is PlanetScale’s Vitess-on-MySQL with branching, deploy requests, and online schema changes; if you are deploying there, MySQL is not optional. Hosted CMS and e-commerce platforms (WordPress, Magento, Shopify back-ends) are MySQL-shaped. Fighting that for a 5% feature gain is not worth the budget.
| Provider | PostgreSQL | MySQL |
|---|---|---|
| AWS | RDS, Aurora PostgreSQL | RDS, Aurora MySQL |
| GCP | Cloud SQL, AlloyDB | Cloud SQL |
| Azure | Flexible Server | Flexible Server |
| Specialist hosts | Neon, Supabase, Crunchy Bridge, Render | PlanetScale, Vitess |
6. How rigorous do you want the SQL surface to be?
PostgreSQL is more rigorous; MySQL is more forgiving. PostgreSQL is case-sensitive by default; MySQL is case-insensitive. PostgreSQL rejects non-aggregated columns in a SELECT with GROUP BY unless you list them; MySQL allows it. PostgreSQL supports both ROWS and RANGE window-frame types with the full set of range units; MySQL is narrower. Writable CTEs (UPDATE/INSERT/DELETE inside a WITH) are PostgreSQL-only. If you write a lot of analytical SQL, this gap shows up daily; if your queries are CRUD against a primary key, you will not notice.
The MVCC and isolation difference (less obvious, big in practice)
PostgreSQL’s MVCC keeps old row versions in the table heap until VACUUM reclaims them. MySQL’s InnoDB keeps old versions in the rollback segment. The practical effects:
- PostgreSQL needs
VACUUM. Autovacuum handles 95% of cases on default settings; on high-write tables, lowerautovacuum_vacuum_scale_factorand watchpg_stat_user_tables.n_dead_tup. - MySQL keeps the table file leaner but the rollback segment can grow unboundedly under long-running transactions. The inverse problem.
- Default isolation differs: PostgreSQL READ COMMITTED, MySQL REPEATABLE READ. Application behaviour under concurrent writes diverges unless you set the level explicitly.
If you have ever had a phantom-read or non-repeatable-read bug, the isolation default is why. Read the PostgreSQL isolation docs and the MySQL InnoDB isolation docs side by side once; the muscle memory pays back later.
Schema migrations: small but daily
PostgreSQL DDL is transactional. BEGIN; ALTER TABLE ...; COMMIT; rolls back cleanly on failure. MySQL 8.0+ has single-statement atomic DDL but most ALTER operations still take a metadata lock and rebuild the table; on a 300 GB users table, that is hours of locked writes. Tools like gh-ost exist precisely because online schema changes are not native to MySQL. PostgreSQL’s ALTER TABLE ADD COLUMN with no default is instantaneous; with a default it has been fast since PG 11. PostgreSQL 18 also retained pg_upgrade optimizer statistics, so the post-upgrade performance dip is much smaller in 2026 than it used to be.
The 6 cases where MySQL is still the right call
- You are deploying on PlanetScale or Vitess. The branching, schema migration, and sharding stack is best-in-class managed MySQL. There is no PostgreSQL equivalent at the same maturity.
- Your team already knows MySQL cold. The wins from PostgreSQL on a new project rarely outweigh re-training time and operational churn for an experienced six-engineer team.
- You are on a hosted CMS or e-commerce that requires it. WordPress, Magento, Shopify back-ends are MySQL-shaped.
- Heavy read workload, simple queries, no JSON. Both perform well; MySQL’s tooling for read replicas is slightly more turnkey out of the box.
- You need active-active multi-primary out of the box. Group replication is more battle-tested than the BSD-licensed PostgreSQL alternatives.
- Your data pipeline is binlog-native. Debezium-on-MySQL CDC pipelines that have been running for years are not worth migrating to PG logical replication for marginal feature gains.
Outside those six, PostgreSQL is the safer pick.
FAQ
Is PostgreSQL faster than MySQL in 2026?
Workload-dependent. PostgreSQL 18’s new asynchronous I/O subsystem reportedly gives up to 3x faster sequential scans, bitmap heap scans, and vacuum operations (per the PG 18 release notes). MySQL 8.4+ is faster on simple primary-key lookups at high concurrency. The Bytebase operating data: most workloads are within 30% either way; an unindexed query is 10x to 1000x slower regardless of engine. Run your real query mix on both before deciding on raw perf.
Should I migrate from MySQL to PostgreSQL?
Not unless you have a specific feature need (JSON indexing, pgvector, transactional DDL, partial indexes) that MySQL cannot meet. Migrations are 4 to 12 weeks of engineering work plus a year of operational learning curve. Greenfield: PostgreSQL. Existing healthy MySQL: stay unless there is a forcing function.
Does PostgreSQL really need VACUUM?
Yes. Autovacuum handles 95% of cases on default settings. Monitor pg_stat_user_tables.n_dead_tup; if it grows unboundedly, autovacuum is misconfigured. Lower autovacuum_vacuum_scale_factor on high-write tables. PostgreSQL 18’s I/O improvements made vacuum noticeably faster in practice; pre-18 tuning advice is still useful but slightly less urgent.
Which has better Django, Rails, and SQLAlchemy support?
Both have first-class drivers. Django’s QuerySet API has slightly more PostgreSQL-specific features (array fields, JSONField with operators, SearchVector); Rails has parity. SQLAlchemy supports both equally. Pick on database needs, not framework support.
What about MariaDB?
MariaDB started as a MySQL fork in 2009 and has diverged. For new projects, the choice is between PostgreSQL and either MySQL or MariaDB; between MySQL and MariaDB, pick the one your hosting provider supports as first-class. MariaDB and MySQL feature sets diverge enough that “MySQL-compatible” claims need testing on your actual queries.
Does MySQL 9.x change the calculus?
Marginally. MySQL 9.x added the VECTOR type, JavaScript stored procedures (Enterprise), and improved hash join performance. None of these close the gap on PostgreSQL’s jsonb indexing, generated-column flexibility, or extension ecosystem. If you were on MySQL anyway, 9.x innovation is a fine track for new features; 8.4 LTS is the safe production pick through 2032.
Sources and further reading
- PostgreSQL 18 release announcement (September 25, 2025).
- Stack Overflow 2025 Developer Survey — Databases.
- Bytebase: PostgreSQL vs MySQL (updated February 2026, maintained by an open-source DB DevSecOps tool that operates both).
- “Why Uber Engineering Switched from Postgres to MySQL”.
- OtterTune: “The part of PostgreSQL we hate the most”.
- PostgreSQL transaction isolation docs and MySQL 8.4 InnoDB isolation docs.
- pgvector.
If you picked PostgreSQL and need to wire it into a backend framework, the FastAPI vs Flask vs Django REST guide is the next read. For the local dev setup that mirrors production, the Docker Compose tutorial walks through Node.js + Postgres + Redis end to end.