The question, stated precisely
You are choosing which relational engine a team will operate for the next several years. That is the decision. It is not a decision about which engine has the better optimiser, the better JSON support or the better replication story, because for the workload most teams actually have, all four of PostgreSQL, MySQL, MariaDB and SQL Server will serve it correctly and fast enough. The engine that fails is almost never the one that ran out of features. It is the one nobody knew how to operate at three in the morning.
Two things are explicitly not being decided here.
Not the data model. If your access patterns are document-shaped, or you need a shard key rather than a primary, that is a different question and MongoDB belongs in the comparison instead. This guide assumes you have already concluded you want SQL, transactions and a schema.
Not the topology. Pooling, read/write splitting and automatic failover are decided after the engine, and for PostgreSQL they are their own decision: see pooling and failover topology.
The three factors that genuinely decide it
1. What the team can already operate
This dominates, and it is uncomfortable because it is not a technical merit. The operational
knowledge that matters is engine-specific and takes months to acquire: knowing that a PostgreSQL
incident is usually vacuum falling behind, a replication slot filling a disk, or a plan change under
stale statistics; knowing that a MySQL incident is usually a gap lock on an unindexed WHERE
clause, an undo tablespace pinned by an open transaction, or semi-synchronous replication having
silently reverted to asynchronous after its timeout. Those are not transferable insights. A team
that has one set and is handed the other starts from zero on the diagnostics.
If you have people who have run one of these engines in production under load, that is the strongest single argument available, and it beats a feature advantage in almost every case.
2. Licence cost, and specifically its shape
For PostgreSQL, MySQL Community and MariaDB, the direct licence cost is not the deciding variable. For SQL Server it frequently is, and the reason is the shape of the cost rather than its size.
Licensing is per physical core, subject to a minimum of four licences per physical processor, sold in two-core packs (Microsoft licensing guidance). Vertical scaling therefore has a linear licence cost with no volume relief: doubling cores doubles the licence count in the same edition. Meanwhile Standard edition caps compute at the lesser of four sockets or 32 cores and the buffer pool at 256 GB in SQL Server 2025, and at 24 cores and 128 GB in 2022 and earlier (Microsoft compute capacity limits).
Put those together and the awkward case appears: you grow past Standard’s ceiling, and the fix is Enterprise, which is charged at the Enterprise per-core rate on every core in the server. That is a step change, not a gradient. It is also frequently triggered by a high-availability requirement rather than by throughput, because full availability groups are an Enterprise feature. So the question to ask early is not “can we afford SQL Server” but “what is the licence bill at the scale and availability level we expect in three years, and what triggers the edition change”.
None of this argues against SQL Server. It argues against choosing it without having drawn that curve, and against choosing it for a workload that fits Standard, needs no availability group and uses no Enterprise feature. That workload is paying for capabilities that are switched off.
3. The one feature you actually depend on
Feature comparisons are close to useless in aggregate and decisive in the particular. The useful exercise is to name the single engine-specific thing your design cannot be built without, and then check that it exists.
| If the design depends on | The engine follows from it |
|---|---|
| PostGIS-class geospatial, or an extension ecosystem generally | PostgreSQL |
| Vector search inside the operational database | PostgreSQL with pgvector, or MySQL 9’s VECTOR type |
| JSON documents as a first-class indexable binary type | PostgreSQL, or MySQL - MariaDB stores JSON as text, its JSON type being an alias for LONGTEXT |
| Lateral derived tables, rich custom types, sophisticated analytical SQL | PostgreSQL |
| Existing T-SQL, SSIS, SSRS or Windows-authenticated estate | SQL Server |
| Galera-style synchronous multi-master for availability | MariaDB |
| An existing MySQL replication topology you must join as a replica | MySQL, or MariaDB - MariaDB can replicate from MySQL, but MySQL cannot replicate from MariaDB |
If nothing on your list is engine-specific (and for a typical transactional application nothing is), this factor does not decide anything, and factor 1 wins by default.
The factor most people over-weight: managed-service availability
This used to be a real differentiator and is now mostly a tie. Every major cloud offers managed PostgreSQL and MySQL; SQL Server is available both as a managed instance and as a platform service. It still matters in two narrower forms. First, whether the managed service supports the specific extension or feature you named above, because managed PostgreSQL offerings ship a curated extension list, not all of them. Second, whether taking the managed service removes the failover component you were otherwise going to build, which is a genuine reduction in operational surface and frequently the single biggest reduction in work available here.
The differences that do not decide it
Stated plainly, because they consume most of the discussion:
- Raw throughput on synthetic benchmarks. All four will exceed the requirement of a workload that is not already at the limit of a single machine. When they do not, the cause is almost always a missing index or a plan problem, which is engine-independent.
- MVCC versus undo-based versioning. Real difference, real operational consequences - dead tuples and vacuum on one side, undo growth and purge lag on the other - but not a reason to prefer either. You are choosing which failure mode to learn.
- Default isolation level. PostgreSQL defaults to
READ COMMITTED, InnoDB toREPEATABLE READ. This matters enormously for correctness during a migration and hardly at all when choosing greenfield, because you can set it. - JSON support in the abstract. It decides the answer only if JSON is central to the schema. If you have three JSON columns holding webhook payloads, every option is adequate.
- Which project is more “open”. Licence and governance differ, and if that is a procurement constraint it is a constraint, not a technical factor. Do not smuggle it in as one.
A decision path
Work down this list and stop at the first line that applies.
- If a named engine-specific feature is load-bearing in the design, choose that engine. This overrides everything below, because the alternative is building the feature yourself.
- If you are extending or integrating with an existing estate (an established replication topology, a body of T-SQL, an ORM configuration and a set of runbooks), stay on that engine. Migration cost is paid immediately; the benefit is speculative.
- If the team has production experience with one of these engines and not the others, choose that one, because the operational knowledge is the scarce asset and it does not transfer.
- If none of the above applies (genuine greenfield, no strong team experience), choose PostgreSQL. Not because it wins a feature comparison, but because the decision is dominated by optionality: the widest extension ecosystem means the “one feature you depend on” in year three is most likely to be available without a migration, there is no per-core licence step change, and managed offerings exist on every platform. The cost you accept is the vacuum and connection-count discipline described on the PostgreSQL page, and the fact that pooling is a separate component you must run.
- If cost per unit of throughput on commodity hardware is the binding constraint and the workload is simple key-and-range access, MySQL or MariaDB is a defensible answer and step 4 is not a rebuke.
What would change the answer
Revisit this decision when one of these becomes true, and not otherwise:
- The workload stops fitting one machine. None of these four scales writes horizontally without application-level sharding. SQL Server availability groups and failover cluster instances give read-only secondaries at best; Galera is availability, not write scale-out; PostgreSQL logical replication moves rows between clusters but does not partition a workload across them. At that point the question is a sharding or distributed-database question, not this one.
- The licence curve crosses. A SQL Server estate approaching Standard’s core or memory ceiling faces an Enterprise per-core decision. That is the moment to price the alternative properly, including the migration.
- A support window closes. MySQL 8.0 reached end of life on 30 April 2026; MySQL 9.7 is the current LTS with 8.4 supported to April 2029 under premier support (endoflife.date). Running an Innovation release, supported only until the next Innovation release, is a different operational commitment from running an LTS. Check the support policy, not the version number.
- The team changes. Factor 1 is a property of the team, so it expires with the team. This is an argument for writing down why the choice was made, so the next group can tell whether the reason still holds.
- The data model diverges from relational. If documents, time series or vectors become the primary access pattern instead of an adjunct, revisit the model before revisiting the engine.
Common wrong reasons
Choosing PostgreSQL because it has more features. Most of them will not be used, and the ones you do use bring specific operational duties. Vacuum must be tuned per table on anything large, because the default 20% scale factor means waiting for 100 million dead tuples on a 500 million row table. The per-connection process model also means a pooler is effectively mandatory. Choosing PostgreSQL is choosing that work.
Choosing MySQL because it is familiar to hiring managers. Familiarity is factor 1 and is legitimate when the familiarity is real and in your team. Assumed familiarity is not. And note that almost everything people attribute to MySQL is a property of InnoDB, so “we know MySQL” needs to mean “we know InnoDB locking”.
Choosing MariaDB as a drop-in replacement for MySQL. It is not one. Accounts and privileges live
in mysql.global_priv with mysql.user as a non-updatable view; MySQL SHA-256 password accounts
cannot be used at all; GTID formats are incompatible in both directions; performance_schema is off
by default. Choose MariaDB on its own merits (Galera, its storage-engine range, its own support
policy) and plan a migration, not a swap.
Choosing SQL Server because of the tooling. The tooling is good and it is not what you are buying. What you are buying is an engine whose edition limits decide your architecture before you write a query, and whose licence cost is linear in cores. If the tooling is the reason, cost the licence first.
Choosing anything because a benchmark said so. Published benchmark results describe the benchmark’s schema, hardware and tuning, none of which are yours. If throughput is genuinely the question, test your own queries on your own data. If you are not going to do that, throughput is not actually the question.
Related
- PostgreSQL - MVCC, vacuum, WAL durability
- MySQL - InnoDB, gap locks, replication
- MariaDB - where it has diverged from MySQL
- SQL Server - edition limits and core licensing
- MongoDB - if the model is not relational after all
- Pooling and failover topology - the next decision