PostgreSQL and MySQL are the two most widely deployed open-source relational databases. Both store data in tables, both use SQL, and both run on every major cloud provider. Yet they make different trade-offs, and choosing the wrong one for your project can mean painful migrations later. This guide compares them honestly so you can make an informed decision — not just a tribal one.
A Brief Background
MySQL was created in 1995 and acquired by Oracle in 2010. It is known for speed, simplicity, and near-universal hosting support. The LAMP stack (Linux, Apache, MySQL, PHP) made it the default database for a generation of web applications. MariaDB is a popular fork created after the Oracle acquisition, with full MySQL compatibility but independent development.
PostgreSQL (pronounced "post-gress-Q-L", often just "Postgres") traces its roots to UC Berkeley in the 1980s. It has a reputation for standards compliance, advanced features, and correctness over raw speed. It is the database behind Apple's iCloud infrastructure, Instagram's data layer at scale, and Supabase — one of the fastest-growing developer platforms today.
SQL Standards Compliance
PostgreSQL is significantly more SQL-compliant than MySQL. This matters for portability — standard SQL is more likely to run without modification on another database if you ever need to migrate.
A well-known historical difference: MySQL's default mode allowed inserting invalid data silently (truncating strings, storing zero-dates for invalid inputs). PostgreSQL enforces constraints strictly by default — if you try to insert a string longer than VARCHAR(50), it throws an error rather than silently truncating it. Modern MySQL (5.7+) in strict mode is much better, but PostgreSQL has always been strict.
Data Types
PostgreSQL has a significantly richer type system:
PostgreSQL-only types worth knowing
- JSONB — Binary JSON with full indexing support. You can index individual JSON fields and query them efficiently. MySQL has a JSON type but its indexing story is weaker.
- Arrays — Native array columns:
tags TEXT[]stores multiple values without a join table. - UUID — Native UUID type with optimised storage (16 bytes) and a dedicated
gen_random_uuid()function built in. - Range types —
daterange,tsrange,int4rangefor storing ranges of values natively, with overlap operators (&&). - ENUM types — Defined at the schema level; both databases support this but PostgreSQL's implementation is more robust.
- Custom types and domains — Create a
DOMAINthat is an integer with a constraint (e.g., must be positive). MySQL has no equivalent.
JSONB in practice
-- PostgreSQL — store and index structured JSON
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
specs JSONB
);
CREATE INDEX idx_products_specs ON products USING GIN (specs);
-- Query by a JSON field
SELECT name FROM products
WHERE specs @> '{"color": "red"}';
-- Update a single JSON field without rewriting the whole document
UPDATE products SET specs = specs || '{"in_stock": false}' WHERE id = 42;
Performance
This is where the "MySQL is faster" myth lives. The reality is nuanced:
MySQL is faster for simple read-heavy workloads. Benchmarks on simple SELECT queries with InnoDB consistently show MySQL outperforming PostgreSQL, sometimes by 20–30%. For a blog, a product catalogue, or any application doing mostly straightforward lookups, MySQL's query planner overhead is lower.
PostgreSQL is faster for complex queries. Joins across multiple large tables, window functions, CTEs (Common Table Expressions), and queries with aggregations often run faster on PostgreSQL because its query planner is more sophisticated. It can do parallel query execution, partial indexes, and expression indexes that MySQL cannot.
Both scale to billions of rows with proper indexing. The database choice rarely becomes a bottleneck before application-level issues (N+1 queries, missing indexes, lack of caching) do.
Advanced Features: Where PostgreSQL Wins
Window Functions
Window functions let you compute aggregates over a sliding window of rows without collapsing them into a group. PostgreSQL has supported them since version 8.4 (2009). MySQL added basic window function support in 8.0 (2018), but PostgreSQL's implementation is more complete:
-- Rank posts by view count within each category
SELECT
title,
category,
view_count,
RANK() OVER (PARTITION BY category ORDER BY view_count DESC) AS rank
FROM posts;
Full-Text Search
PostgreSQL has a built-in full-text search system with stemming, ranking, and highlighting that is often good enough to replace Elasticsearch for medium-scale search. MySQL also has full-text search, but PostgreSQL's implementation handles complex queries and multiple languages better.
Extensions
PostgreSQL's extension system is one of its most powerful features. Notable extensions:
- PostGIS — turns PostgreSQL into a full geographic information system
- pgvector — vector similarity search for AI/ML embeddings (critical for AI applications in 2026)
- pg_partman — automated table partitioning
- Timescale — time-series data optimisation
MySQL has no equivalent extension ecosystem.
Transactions and Concurrency
PostgreSQL uses MVCC (Multiversion Concurrency Control) throughout, including in DDL statements (CREATE TABLE, ALTER TABLE). You can run schema migrations inside transactions and roll them back if something goes wrong. MySQL also uses MVCC for DML but DDL statements are auto-committed and cannot be rolled back — a broken migration cannot simply be undone.
Where MySQL Still Has the Edge
Hosting Support
MySQL is available on virtually every shared hosting plan. cPanel installs MySQL by default. If you are building a PHP application on budget shared hosting, MySQL is almost certainly what is available. PostgreSQL is common on VPS and cloud platforms (AWS RDS, DigitalOcean Managed Databases, Google Cloud SQL) but less common on entry-level shared hosting.
Replication Simplicity
MySQL's built-in replication (primary-replica) is simpler to configure than PostgreSQL's streaming replication. For teams doing DIY replication on a VPS, MySQL's setup documentation and community resources are more accessible.
Familiarity
If your team knows MySQL and the application is a standard CRUD app with no complex queries, switching to PostgreSQL provides no practical benefit and introduces learning overhead. Don't change what isn't broken.
Cloud Database Options in 2026
| Service | Database | Free Tier |
|---|---|---|
| Supabase | PostgreSQL | Yes (500 MB) |
| PlanetScale | MySQL (Vitess) | Paid plans only |
| Neon | PostgreSQL (serverless) | Yes (0.5 GB) |
| Railway | PostgreSQL or MySQL | Yes (5 USD credit) |
| AWS RDS | Both | 12 months free tier |
Framework Compatibility
Every major framework works well with both databases:
- Laravel (PHP) — Eloquent ORM supports both; MySQL is more common in tutorials but PostgreSQL works identically
- Django (Python) — Officially recommends PostgreSQL; some features like ArrayField only work with PostgreSQL
- Ruby on Rails — ActiveRecord supports both; Rails' full-text search and UUID support are better with PostgreSQL
- Prisma (Node.js) — Excellent support for both; JSONB queries are richer with PostgreSQL
The Verdict
Choose PostgreSQL if you are starting a new project on a VPS or cloud platform, if you need JSONB, advanced queries, AI/vector search, or PostGIS, or if you value SQL standards compliance and safe schema migrations.
Choose MySQL if you are on shared hosting where PostgreSQL is not available, if your team is deeply familiar with MySQL, or if you are building a simple read-heavy application and want the slight performance edge on basic queries.
In 2026, for greenfield projects on cloud infrastructure, PostgreSQL is the default choice. The ecosystem has caught up on documentation and tooling, cloud providers offer managed PostgreSQL at the same price points as MySQL, and the advanced features — especially pgvector for AI workloads — make it the more future-proof option.
CREESOL