Which database should I choose for my startup: Postgres or MySQL? · DpkDB
Which database should I choose for my startup: Postgres or MySQL?
A founder's guide to choosing PostgreSQL or MySQL: team experience, managed hosting, scaling paths, extensions, licensing, switching cost, and a clear "pick PostgreSQL unless" rule.
Choose PostgreSQL for a new startup unless one of three things is true: your engineers have run MySQL in production and have not run PostgreSQL, your product is built on a platform that requires MySQL, or you have concrete evidence that you will need horizontal sharding early and want the Vitess path. In those cases choose MySQL. Both databases will carry a company from its first customer to very large scale, so this decision deserves an afternoon, not a month. Backups, migration discipline, indexing and connection pooling will affect your uptime far more than which of the two you picked.
the people who will be on call know MySQL operations and do not know PostgreSQL operations, or
a platform, framework or product you depend on is built for MySQL, or
you can state now, with numbers from a real workload, why a single primary with replicas will not be enough, and you prefer Vitess to the PostgreSQL alternatives.
If none applies, PostgreSQL gives a small team more capability per system operated.
Factor 1: what the team already knows
This factor outweighs every feature comparison. Operating a database means knowing how to restore a backup under pressure, read a query plan, find the session that is blocking everyone, add an index to a large table without an outage and judge whether replication lag is normal. That knowledge takes years to build and is specific to the engine. An engineer who knows that a forgotten idle in transaction session stops vacuum in PostgreSQL does not automatically know that the same mistake grows the undo history in InnoDB.
If your first engineers have that experience with MySQL, the feature advantages of PostgreSQL will not pay for the incidents caused by learning it on live customer data. The reverse is also true. If nobody has operational experience with either, you are learning one from scratch, and the rule above applies.
Factor 2: managed hosting
A startup should not run its own database servers without a specific reason. Managed services handle patching, backups, failover and monitoring, and both engines are well served.
timestamptz doesn't store a time zone, and timestamp silently drops the offset you pass in. What each type really stores, where timestamp causes bugs and the one case where it's right.
Vitess, TiDB (MySQL-compatible protocol and syntax)
Some distinctions that matter when choosing among them:
Stock engine or compatible engine. RDS, Cloud SQL and the Azure services run the community database with a managed control plane. Aurora is, in AWS's words, compatible with MySQL and PostgreSQL but has its own storage layer. TiDB is a different database that speaks the MySQL protocol and supports most MySQL syntax, with a documented list of unsupported features. Compatible engines can be excellent, and they also mean that behaviour, versions and extension support follow the vendor.
Platforms around the database. Supabase packages PostgreSQL with authentication, file storage and auto-generated APIs, which suits a small team that wants a backend quickly. Neon separates storage from compute and offers database branching, which creates copy-on-write clones for development and CI. PlanetScale built its service on Vitess for MySQL and now also offers PostgreSQL. These platforms move quickly, so read their current documentation, not a comparison written a year ago.
What to check before signing up:
Point-in-time recovery, and how far back it reaches.
Which major versions are offered and how upgrades work.
For PostgreSQL, the list of supported extensions. A managed service only allows the extensions it has approved.
Whether a connection pooler is included.
How you get your data out: a logical dump always works, and logical replication or binary log access makes a low-downtime exit possible.
At this level of the market the two engines are equally easy to buy. The newer developer platforms lean toward PostgreSQL. The largest cloud providers treat both as first-class.
Factor 3: the scaling path
The path is the same for both and most companies stop at step two or three.
A bigger machine. Managed instances scale up a long way, and this step needs no code changes.
Read replicas. Move reporting and read-heavy endpoints to replicas. Both engines support this natively. The application has to tolerate replication lag on those reads.
Caching and query work. Fixing the worst queries and caching hot reads often removes the need for the next steps.
Partitioning. Split very large tables by time or tenant inside one server. PostgreSQL has declarative partitioning with foreign key support. MySQL partitioning works but InnoDB does not support foreign keys on partitioned tables.
Sharding. Split data across servers.
Sharding is where the ecosystems differ.
Vitess is a sharding and clustering layer for MySQL, created at YouTube and now a graduated Cloud Native Computing Foundation project. Applications connect to it as if it were one MySQL server and it routes queries to shards, handles resharding and manages failover. It has a long production history at large scale. It also restricts what you can do across shards, so check its MySQL compatibility documentation against your queries.
Citus is a PostgreSQL extension that distributes tables across nodes and keeps small shared tables on every node as reference tables for joins. Because it is an extension, you keep PostgreSQL's types, indexes and most of its SQL. It suits multi-tenant applications where almost every query filters on a tenant ID.
Both require a distribution key chosen early, and both make cross-shard transactions and joins more expensive. Neither is something to adopt before you need it. If you already expect to shard, which is rare and should be supported by numbers, Vitess is the more established route and is a legitimate reason to start on MySQL.
Factor 4: extensions that replace extra infrastructure
For a small team, every additional system is another thing to deploy, secure, monitor and keep consistent with the primary database. PostgreSQL's extensions let you defer several of them.
Need
PostgreSQL
MySQL
Semi-structured data
jsonb with GIN indexes
JSON type with indexes on generated columns
Text search
Built-in full-text search with stemming and ranking
Built-in FULLTEXT indexes
Geospatial
PostGIS extension
Built-in spatial types and SPATIAL indexes
Vector similarity search
pgvector extension with HNSW and IVFFlat indexes
VECTOR type in MySQL 9; no vector index in the Community Edition
Background job queue
SELECT ... FOR UPDATE SKIP LOCKED
SELECT ... FOR UPDATE SKIP LOCKED
Vector search is the clearest current example. A product that adds semantic search or retrieval for a language model needs nearest-neighbour queries over embeddings. With pgvector that is one extension and one index in the database you already run:
CREATE EXTENSION vector;
CREATE TABLE documents (
id bigint GENERATED ALWAYS ASIDENTITYPRIMARY KEY,
tenant_id bigintNOT NULL,
body text NOT NULL,
embedding vector(1536) NOT NULL
);
CREATE INDEX documents_embedding_idx
ON documents USING hnsw (embedding vector_cosine_ops);
SELECT id, body
FROM documents
WHERE tenant_id =42ORDERBY embedding <=> $1
LIMIT 10;
The embeddings live in the same transaction as the rows they describe, and filters and joins against the rest of your schema are ordinary SQL. MySQL 9 has a VECTOR data type, but its manual states that a VECTOR column cannot be used as any kind of key and that the DISTANCE() function is available only in MySQL HeatWave and MySQL AI, not in the Community or Commercial distributions. On MySQL you would add a separate vector store.
PostGIS does the same for location features, adding geometry and geography types, spatial indexes and a large function library. MySQL's built-in spatial support covers common cases such as distance and containment queries.
The qualification is that "one database for everything" is a way to start, not a permanent architecture. A dedicated search engine or vector database may be justified later. Postponing it until you have revenue and an operations team is the point.
Factor 5: licensing and governance
For a company that runs the database as a service behind its own product, licensing is not a practical difference. It matters in two situations.
You distribute the database inside your product, for example in an on-premises appliance or installer. PostgreSQL's license is permissive, similar to BSD and MIT, and places no conditions on that. MySQL Community Edition is GPLv2. Oracle sells commercial licenses for vendors who want to distribute MySQL with their software without the GPL's source obligations. Get legal advice if this is your model.
You care who controls the roadmap. PostgreSQL is developed by a community with contributors from many companies and no single owner. MySQL is owned by Oracle, which develops it in the open under the GPL and sells an Enterprise Edition with extra features. MariaDB is a fork of MySQL, also GPLv2, with its own roadmap and growing incompatibilities, so it is a third option to evaluate and not a drop-in guarantee. Neither governance model has prevented either database from being a safe long-term choice so far. The permissive license and the multi-vendor community are the reasons the risk is lower with PostgreSQL.
Factor 6: hiring
Both databases are widely taught and widely used, and application developers move between them quickly because the SQL they write day to day is nearly the same. The scarce skill is deep operational experience, and it is scarce for both. Managed services reduce how much of it you need early on.
Look at your stack's community to see which pairing will be most familiar to candidates. The PHP world, including WordPress and much Laravel deployment, has a long MySQL tradition. Hire for the stack you have, and expect a good engineer to learn the other engine.
Factor 7: the cost of switching later
Switching between PostgreSQL and MySQL is possible, and tools such as pgloader and AWS Database Migration Service move the data. The data is the easy part. The cost is in everything that depends on engine behaviour:
SQL dialect. Upserts, RETURNING, JSON operators, date functions and full-text queries all need rewriting.
Semantics. MySQL's default string comparison is case-insensitive and PostgreSQL's is case-sensitive, so uniqueness and login lookups change meaning. Default isolation levels differ, and booleans and time zone handling do too. See Should I use timestamp or timestamptz in PostgreSQL?.
Schema features. Arrays, partial indexes and exclusion constraints on one side, unsigned integers and ON UPDATE CURRENT_TIMESTAMP on the other.
Operations. Backups, monitoring, runbooks, replication topology and every engineer's instincts.
Cutover. A production migration needs change data capture or dual writes, verification and a rollback plan.
The cost rises with every table and every query written. Early on, a switch is a small task. After a few years of development it is a long project that delivers no customer-visible feature. That is the argument for making a deliberate choice now, and also for not agonising over it: the price of a wrong choice is rarely a failed company and usually a migration you would prefer to avoid.
What matters more than the choice
These decide whether the database causes you an outage in the first two years.
Backups with tested restores. Enable point-in-time recovery and restore into a scratch instance on a schedule. An untested backup is a guess.
Side-by-side SQL for the differences web developers hit daily: quoting, case sensitivity, identity columns, RETURNING, upserts, booleans, JSON, GROUP BY, full-text search, migrations and time zones.
A session doing nothing can stop VACUUM from cleaning every table and stall your next migration. Find them, kill them safely and prevent them with the right timeouts.