PostgreSQL vs MySQL

Short answer: choose PostgreSQL for a new project. It has a richer feature set, stricter correctness, a far better extension ecosystem, and a genuinely permissive license. The performance gap that once favored MySQL for simple read-heavy workloads has largely closed, and PostgreSQL now wins on most dimensions that matter over a project's life.

That said, MySQL is not a bad choice and the gap is narrower than partisans claim. It remains excellent, it powers enormous systems, its replication is simpler to operate, and if your team already knows it well or your hosting favors it, that's a legitimate reason to stay. The wrong database your team is expert in usually beats the right database nobody knows.

Where the choice genuinely matters is at the edges: complex queries, data integrity requirements, geospatial or vector work, and anything needing an extension. Those all favor PostgreSQL, and they're the areas where switching later is most expensive.

TL;DR

Head-to-Head

Where PostgreSQL Wins

Query power

For analytical and reporting queries, PostgreSQL's optimizer and feature set are meaningfully ahead. MySQL 8.0 closed a lot of this gap — it has CTEs and window functions now — and PostgreSQL remains stronger on the harder cases.

JSONB

MySQL's JSON type is functional and lacks JSONB's operator richness and GIN indexing. In MySQL you index a JSON path with a generated column plus an index on it — workable, more manual. See PostgreSQL JSONB.

Extensions

This is arguably PostgreSQL's decisive advantage, and it compounds over a project's life:

Each of these replaces a separate system you'd otherwise run. pgvector alone means many teams don't need a dedicated vector database; PostGIS is why nearly all serious geospatial work is PostgreSQL. MySQL has plugins, and nothing comparable in breadth.

Strictness by default

MySQL historically silently truncated — inserting 99999 into a SMALLINT stored 32767 and returned success, and an over-long string was cut short. MySQL 8.0 enables strict mode by default, which fixes this, and it remains worth verifying sql_mode on any inherited installation because a permissive setting produces silent data corruption.

Correctness details that bite

MySQL's DDL is not transactional — a failed migration leaves the schema partially altered, which is a materially worse operational experience. PostgreSQL also has proper CHECK constraint enforcement (MySQL ignored CHECK entirely until 8.0.16) and stricter GROUP BY handling.

Where MySQL Wins

Replication that's simpler to run

MySQL's replication has been the default deployment model for decades, its failure modes are extremely well documented, and Group Replication / InnoDB Cluster give you a supported multi-primary and automatic-failover story out of the box. PostgreSQL's streaming and logical replication are powerful, with more configuration surface, and high availability typically means adding Patroni, repmgr, or a managed service. See PostgreSQL High Availability.

Cheaper connections

PostgreSQL forks a process per connection, costing several megabytes each. A thousand connections is a real problem, which is why connection pooling with PgBouncer is effectively mandatory at scale. MySQL uses threads, which are cheaper, so it tolerates high connection counts more gracefully.

This matters most for serverless and high-concurrency deployments, where connection count is the binding constraint. PostgreSQL's answer is a pooler; it works well and it's another component.

Simple read-heavy workloads at very high concurrency

For workloads dominated by simple primary-key reads at very high concurrency, MySQL with InnoDB has historically had a small edge. The gap has narrowed substantially and is now small enough that it rarely decides a choice — but it's real, and it's part of why MySQL remains popular at some large web properties.

Less routine maintenance to think about

PostgreSQL's MVCC leaves dead tuples that VACUUM reclaims. Autovacuum handles this well and needs tuning on high-churn tables, and transaction ID wraparound is a genuine operational hazard if vacuum falls badly behind. InnoDB's purge handles the equivalent more invisibly. This is a real difference in operational attention required.

Ubiquitous cheap hosting

Every shared host and low-cost provider offers MySQL. PostgreSQL availability is good and less universal at the bottom of the market. Irrelevant if you're on a cloud provider; relevant for small projects.

Performance

The honest position: at ordinary scale, neither is your bottleneck. Both handle tens of thousands of transactions per second on modern hardware. Your schema design, your indexes, and your queries will determine performance long before the engine choice does.

Benchmarks favoring one or the other almost always reflect a specific workload and configuration. Treat any general "X is faster" claim with suspicion, and benchmark your own schema and queries if it matters. See Benchmarking and Query Optimization.

The Decision

If you're genuinely undecided, pick PostgreSQL. The feature ceiling is higher, the license is cleaner, and the things it does better (complex queries, extensions, integrity) are the things that get expensive to work around later. Migrating between them is possible and not pleasant.

Managed options remove most of the operational difference: AWS RDS and Aurora offer both, Supabase and Neon are PostgreSQL, and PlanetScale is MySQL-compatible with branching. The managed platform's features may reasonably decide the choice for you.

Best Practices

If you choose PostgreSQL, put a connection pooler in front of it

PgBouncer in transaction mode, or your provider's built-in pooler. Process-per-connection means a few hundred direct connections is a limit you will hit, and serverless deployments hit it immediately. This is the single most common PostgreSQL operational mistake. See PostgreSQL Connection Pooling.

If you choose MySQL, verify strict mode

8.0+ defaults are good; inherited installations and some managed configurations are not. A permissive sql_mode silently corrupts data, which is much worse than a failed insert.

Enable query statistics on either

pg_stat_statements on PostgreSQL, the Performance Schema on MySQL. Both are essentially free and both are how you find the query actually causing your problem rather than the one you assume is.

Monitor autovacuum on PostgreSQL

Track dead tuple counts, autovacuum lag, and — critically — transaction ID age. Wraparound protection forcing a shutdown is an avoidable outage, and high-churn tables usually need per-table autovacuum tuning.

Use utf8mb4 on MySQL, never utf8

MySQL's utf8 is a three-byte subset that cannot store emoji or many CJK characters. utf8mb4 is real UTF-8. This trips people up constantly and is the default in 8.0.

Don't switch databases for performance without measuring

The overwhelming majority of "we need to migrate for performance" situations are a missing index, an N+1 query, or absent connection pooling. Profile first; migration is a large project with real risk and usually solves nothing the profiling wouldn't have.

Consider the managed platform, not just the engine

Aurora, Cloud SQL, Supabase, Neon, and PlanetScale differ substantially in branching, autoscaling, failover behavior, and cost. For many teams the platform's characteristics matter more than PostgreSQL-vs-MySQL, and it's worth evaluating them together.

Common Mistakes

Assuming MySQL is faster because it's "simpler"

Running PostgreSQL without a pooler

Using utf8 in MySQL

Relying on non-transactional DDL

Ignoring PostgreSQL vacuum until it's an incident

Choosing based on a benchmark blog post

FAQ

Which is better for a new project in 2026?

PostgreSQL, for most projects. The feature set, extension ecosystem, standards compliance, and permissive license all favor it, and the historical performance argument for MySQL has largely evaporated. MySQL remains a perfectly good choice, particularly where the team's existing expertise or a need for Group Replication points that way.

Is MySQL still faster for reads?

Marginally, for very high-concurrency simple key lookups, and the gap has narrowed enough that it rarely decides anything. For complex queries PostgreSQL is generally faster. Both are far faster than a badly indexed schema in either.

Can I migrate from MySQL to PostgreSQL?

Yes, and it's real work. Tools like pgloader handle bulk schema and data conversion well. What takes the time is application-level: SQL dialect differences (LIMIT/OFFSET is fine, but auto-increment, string functions, GROUP BY behavior, and date handling all differ), ORM configuration, stored procedures, and testing. Plan weeks rather than days for a substantial application, and use CDC for a low-downtime cutover.

What about MariaDB?

A MySQL fork created after Oracle's acquisition, maintained by the original MySQL developers, fully open source with no dual-license concern. It's largely drop-in compatible and has diverged over time — some features exist in one and not the other. It's a reasonable choice if you want MySQL semantics without Oracle, and it has a smaller ecosystem and less cloud-provider support than either PostgreSQL or MySQL.

Does the license actually matter?

For most users, no — MySQL's GPL is fine for running a service, since you're not distributing the database. It matters if you're embedding or redistributing MySQL as part of a product, where the GPL obligations apply and you'd need Oracle's commercial license. PostgreSQL's permissive license has no such consideration, which is one reason it's favored by companies building products on top of a database.

Which has better cloud support?

Both are universally available. PostgreSQL arguably has the more interesting current ecosystem — Supabase, Neon, and Aurora's PostgreSQL-compatible edition all offer distinctive capabilities like branching and scale-to-zero. MySQL has Aurora MySQL and PlanetScale, whose branching and non-blocking schema changes are genuinely excellent. Evaluate the platform alongside the engine.

Related Topics

References