---
title: SQLite vs PostgreSQL vs MySQL vs MariaDB vs DuckDB
slug: sqlite-vs-postgres-vs-mysql
url: "https://toolweight.dev/compare/sqlite-vs-postgres-vs-mysql"
question: Should I use SQLite, PostgreSQL or MySQL?
tools: 5
fields: 26
last_verified: 2026-07-01
freshness: 62%
verify_cadence: 30d
license: CC-BY-4.0
---

# SQLite vs PostgreSQL vs MySQL

> **Should I use SQLite, PostgreSQL or MySQL?**
>
> Use SQLite when one process owns the data and writes are modest. Use PostgreSQL when concurrent writers, complex queries or extensions like pgvector matter, and you can afford to run it. Use MySQL or MariaDB when replication and online schema changes on huge tables matter more than SQL expressiveness. DuckDB is for analytics, not serving.

## At a glance

|  |  |
| --- | --- |
| Canonical | https://toolweight.dev/compare/sqlite-vs-postgres-vs-mysql |
| Tools compared | 5 |
| Fields compared | 26 |
| Last verified | 2026-07-01 (22d ago) |
| Verify cadence | 30d |
| Freshness | 62% (mean cell confidence) |
| Killer field | operational_burden |
| Scoring | Not ranked — this category compares, it does not rank |
| Licence | CC-BY-4.0 — https://creativecommons.org/licenses/by/4.0/ |

## Comparison

### Engine & SQL

| Tool | Embedded or server | Concurrency model | Write concurrency | Isolation levels | JSON support | Full-text search | Vector search | Type strictness | ALTER TABLE | Max database size |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| PostgreSQL | Server (client/server) | MVCC (heap row versions) | Concurrent writers (row-level) | Read committed, Repeatable read, Serializable | Binary JSONB + indexes | Built-in | Extension | Static, strict | Minimal | — |
| MariaDB | Both | MVCC (undo log) | Concurrent writers (row-level) | Read uncommitted, Read committed, Repeatable read, Serializable | Text functions only | Built-in | Native type + ANN index | Static, coercing | Moderate | 64 TB |
| MySQL | Server (client/server) | MVCC (undo log) | Concurrent writers (row-level) | Read uncommitted, Read committed, Repeatable read, Serializable | Binary JSON type | Built-in | Native type | Static, coercing | Moderate | 64 TB |
| SQLite | Embedded (in-process) | Reader/writer locking | Single writer | Serializable | Text functions only | Extension | Extension | Dynamic (per-value) | Severe (rebuild required) | 256 TB |
| DuckDB | Embedded (in-process) | MVCC (single process) | Single writer | Snapshot | Text functions only | Extension | Extension | Static, strict | Moderate | — |

### Operations

| Tool | Replication | PITR | Online schema change | Connection model | Default max conns | Managed options | Ops burden |
| --- | --- | --- | --- | --- | --- | --- | --- |
| PostgreSQL | Built-in async + synchronous | ● | ◐ | Process per connection | 100 | Neon, Supabase, Amazon RDS, Amazon Aurora, Google Cloud SQL, Azure Database, PlanetScale | 4 |
| MariaDB | Built-in async + synchronous | ● | ● | Thread per connection | 151 | Amazon RDS, Google Cloud SQL, MariaDB SkySQL | 3 |
| MySQL | Built-in async + synchronous | ● | ● | Thread per connection | 151 | Amazon RDS, Amazon Aurora, Google Cloud SQL, Azure Database, PlanetScale | 3 |
| SQLite | Third-party only | ◐ | ○ | In-process (no connections) | — | Turso, Cloudflare D1, Fly.io LiteFS | 1 |
| DuckDB | None | ○ | ○ | In-process (no connections) | — | MotherDuck | 1 |

### Ecosystem

| Tool | Extension ecosystem | Client libraries | Migration tooling | GitHub stars | Positioning |
| --- | --- | --- | --- | --- | --- |
| PostgreSQL | 5 | 5 | 5 | 18,000 | The world's most advanced open source relational database. |
| MariaDB | 3 | 4 | 3 | 6,000 | The open source relational database, made by the original developers of MySQL. |
| MySQL | 2 | 5 | 4 | 11,000 | The world's most popular open source database. |
| SQLite | 4 | 5 | 3 | 8,000 | Small. Fast. Reliable. Choose any three. |
| DuckDB | 4 | 3 | 2 | 33,000 | DuckDB is a fast in-process analytical database. |

### Licence & governance

| Tool | Licence | Embed in closed source | Governance |
| --- | --- | --- | --- |
| PostgreSQL | PostgreSQL Licence (BSD-style) | ● | Community project |
| MariaDB | GPL-2.0 | ◐ | Foundation |
| MySQL | GPL-2.0 or commercial | ○ | Single vendor |
| SQLite | Public domain | ● | Independent team |
| DuckDB | MIT | ● | Foundation |

### History

| Tool | First release |
| --- | --- |
| PostgreSQL | 1997-01-29 |
| MariaDB | 2009-10-29 |
| MySQL | 1995-05-23 |
| SQLite | 2000-08-17 |
| DuckDB | 2019-06-26 |

## Field registry

| Field | id | Group | Type | Unit | Better | Default weight | Definition |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Embedded or server | `embedded_or_server` | features | enum | — | n/a | 0 | Whether the engine runs inside your application process as a library, as a separate daemon you connect to over a socket, or ships both. |
| Concurrency model | `concurrency_model` | features | enum | — | n/a | 0 | How the engine isolates concurrent transactions: lock-based, or multi-version with old row versions kept in the heap, in an undo log, or in process memory. |
| Write concurrency | `write_concurrency` | features | enum | — | n/a | 0 | Whether two write transactions can commit at the same time against the same database, or writes are serialised to one at a time. |
| Isolation levels | `isolation_levels` | features | multi-enum | — | n/a | 0 | SQL isolation levels the engine implements with distinct semantics; levels it accepts but silently upgrades are excluded and noted. |
| JSON support | `json_support` | features | enum | — | higher | 5 | Whether JSON is stored as text with helper functions, as a parsed binary column type, or as a binary type with a general index (GIN or multi-valued) over its contents. |
| Full-text search | `full_text_search` | features | enum | — | higher | 4 | Whether a ranked text index (BM25, tsvector, FULLTEXT) is part of the core engine, available as a loadable extension, or absent. |
| Vector search | `vector_search` | features | enum | — | higher | 6 | Support for storing embeddings and running nearest-neighbour queries: absent, a native column type with exact scans only, a mature extension, or a native type with an approximate index in the open-source build. |
| Type strictness | `type_strictness` | features | enum | — | n/a | 0 | Whether column types are advisory and values carry their own type, enforced but with implicit coercion or truncation, or enforced with errors on lossy conversion. |
| ALTER TABLE | `alter_table_limits` | features | enum | — | higher | 6 | How much of the schema you can change in place. Severe means most changes beyond ADD COLUMN need a full table rebuild; minimal means near-complete DDL inside a transaction you can roll back. |
| Max database size | `max_db_size` | features | bytes | — | n/a | 0 | The documented hard ceiling for one database or tablespace. Null where the project documents no limit; the note gives the practical wall operators hit first. |
| Replication | `replication` | operations | enum | — | higher | 7 | Replication shipped with the engine itself: none, third-party tooling only, asynchronous followers, or asynchronous plus a synchronous or quorum-committed mode. |
| PITR | `pitr` | operations | tristate | — | higher | 7 | Point-in-time recovery: can you restore to an arbitrary moment before an incident using a base backup plus a shipped write-ahead or binary log? Partial means only via third-party tooling. |
| Online schema change | `online_schema_change` | operations | tristate | — | higher | 7 | Whether a large table's schema can be changed while writes continue, without a long exclusive lock, using either the engine's own online DDL or well-established shadow-table tooling. |
| Connection model | `connection_model` | operations | enum | — | n/a | 0 | What the server allocates per client connection, which sets how badly an oversized or serverless connection pool hurts. |
| Default max conns | `default_max_connections` | operations | number | — | n/a | 0 | Out-of-the-box concurrent client connection limit in a default configuration. Null for embedded engines, where the concept does not apply. |
| Managed options | `hosted_options` | operations | multi-enum | — | higher | 5 | Notable managed services that run this engine for you, as a proxy for how easy it is to stop operating it yourself. Curated, not exhaustive. |
| Ops burden | `operational_burden` | operations | score | — | lower | 9 | 1–5, lower is less work. 1 = a file your process opens: no daemon, no upgrade dance. 2 = one process, but you own the backups. 3 = a server with users, connection limits and a replica to monitor. 4 = all of that plus vacuum or bloat management, connection pooling and major-version upgrades that need a migration plan. 5 = a cluster with a full-time owner. |
| Extension ecosystem | `extension_ecosystem` | ecosystem | score | — | higher | 6 | 1–5. 1 = no extension mechanism. 2 = pluggable storage engines or components, little third-party use. 3 = a documented plugin API with a handful of production-grade plugins. 4 = a healthy third-party ecosystem installable without patching the source. 5 = hundreds of extensions, and managed hosts ship a curated subset. |
| Client libraries | `client_library_maturity` | ecosystem | score | — | higher | 5 | 1–5 for driver and ORM quality across mainstream languages. 5 = first-class, actively maintained drivers plus full ORM and query-builder support everywhere. 3 = official drivers for the major languages, thin ORM coverage. 1 = one language, community-maintained. |
| Migration tooling | `migration_tooling` | ecosystem | score | — | higher | 6 | 1–5 for schema-migration tooling maturity, weighted towards zero-downtime changes on large tables. 5 = several mature frameworks plus dedicated online-change tools. 2 = migrations exist but you write the safety yourself. |
| GitHub stars | `github_stars` | ecosystem | number | — | n/a | 0 | Stars on the canonical public repository, rounded to the nearest thousand. For SQLite, PostgreSQL and MySQL this is a read-only mirror, so it measures visibility rather than activity. |
| Positioning | `positioning` | ecosystem | text | — | n/a | 0 | The project's own one-line description of itself, quoted from its homepage or documentation. |
| Licence | `licence` | licensing | enum | — | n/a | 0 | The licence the source is distributed under. Dual licensing means the copyleft terms apply unless you buy the commercial option. |
| Embed in closed source | `embedding_freedom` | licensing | tristate | — | higher | 4 | Whether you can ship the engine inside a proprietary product without a commercial licence. Partial means the client library is permissive enough to link, but the server is not redistributable that way. |
| Governance | `governance` | licensing | enum | — | n/a | 0 | Who controls the roadmap and holds the copyright: one company, a small independent team, a non-profit foundation, or a distributed contributor community with no owning entity. |
| First release | `first_release` | timeline | date | — | n/a | 0 | Date of the first public release under the project's current name; the note records earlier ancestry where it exists. |

## Verdict

This page has no score column, and it never will. Every other comparison on toolweight ranks vendors selling roughly the same thing at different prices. These five are engines with different shapes: SQLite is a file format with a query planner attached, PostgreSQL is a process-per-connection MVCC server, MySQL and MariaDB are thread-per-connection MVCC servers tuned for replication, and DuckDB is a columnar analytics engine that happens to speak SQL. Weighting them against each other would produce a number that says more about the weights than the engines. So instead the table is descriptive, and the decision lives in prose.

PostgreSQL is the correct default for most teams, and the reason is boring: it has the widest SQL surface, the best extension ecosystem, and the most people who already know it. pgvector made it the default vector store too, which killed a whole category of standalone databases. What the marketing never mentions is the operational tax. Postgres is the heaviest engine here to run — that is the killer field on this page. Autovacuum tuning, transaction-ID wraparound, bloat, a process per connection so PgBouncer stops being optional past a few hundred clients, and major-version upgrades that mean pg_upgrade or a logical-replication cutover. Managed Postgres exists precisely because self-hosting it well is a job.

SQLite is the most under-used engine here and the most over-claimed by the people who love it. The claims are true: WAL mode gives many concurrent readers, and one machine with an NVMe disk serves an astonishing amount of traffic with zero network hops. The constraints get skipped: one writer at a time, no built-in replication, a twelve-step table rebuild for most schema changes beyond ADD COLUMN, and a backup story that means adopting Litestream or Turso. That is a straight trade, not a warning. One process, short writes, and you are buying a great deal of simplicity.

MySQL and MariaDB are still the right answer more often than the Postgres-shaped internet admits, for one specific reason: changing the schema of a very large table without taking writes offline. Online DDL, INSTANT ADD COLUMN, and a decade of gh-ost and pt-online-schema-change in production make that routine in a way it is not on Postgres. Thread-per-connection also forgives a badly behaved pool. Against that: a narrower SQL surface, a thin extension ecosystem, and a licence question. MySQL is GPLv2-or-commercial under Oracle, MariaDB is GPLv2 under a foundation. Shipping the server inside a product makes that difference the whole decision; running a website makes it noise.

The tree, then. Does more than one process write to this data concurrently? If no, and the working set fits on one disk, use SQLite and turn on WAL mode. If yes: does a meaningful share of your query load look like aggregation over columns rather than fetching rows by key? If so, that half of the workload belongs in DuckDB or a warehouse, not in your OLTP engine, and the remaining half is a smaller problem. Then: do you need extensions — pgvector, PostGIS, TimescaleDB — or window-heavy, CTE-heavy SQL? If yes, PostgreSQL, and budget for the operations. If no, and your actual fear is altering a 500 GB table without downtime, MySQL or MariaDB. If none of that discriminates, it is a genuine tie, and a tie means pick the engine somebody on the team has already debugged at three in the morning.

## Axis 1 — deployment shape

The first question is not which SQL dialect you prefer, it is whether the database is a library or a server. SQLite and DuckDB run inside your process: no daemon, no port, no credentials to rotate, no network hop, no connection pool, and no second thing to monitor. A query is a function call. That collapses an entire layer of your architecture, and the cost is that the database's availability is now your process's availability, and adding a read replica means shipping the file — Litestream, LiteFS, Turso — rather than pointing a replica at a primary.

Server engines charge you a daemon and pay you back with a network boundary. Several app instances, an analyst with psql, a read replica in another region, a bastion host, a migration that runs from CI rather than from whichever container won the race. The detail that catches teams out is the connection model. PostgreSQL forks a process per connection, so a thousand idle Lambda connections is a memory problem and PgBouncer stops being optional; MySQL and MariaDB use a thread per connection and are far more forgiving of a badly configured pool. If your compute is serverless and bursty, that difference matters more than any feature in the table.

## Axis 2 — concurrency profile

SQLite in WAL mode gives you many concurrent readers and exactly one writer. Writes are serialised, so the arithmetic is simple: write transaction duration multiplied by writes per second must stay comfortably below one. Short transactions at a few hundred writes per second are fine on commodity hardware. Long transactions are what kill you, and holding a write transaction open across a network call is the classic way to turn a healthy app into a locked one.

MVCC engines let writers proceed in parallel by keeping old row versions, and then hand you the bill for those versions. On PostgreSQL it arrives as autovacuum, table and index bloat, and transaction-ID wraparound warnings. On InnoDB it arrives as undo-log growth and a history list length that climbs when a long-running read transaction refuses to end. Neither is hard once you know it exists; both are surprises the first time.

One concurrency detail deserves more attention than it gets: the default isolation levels differ. PostgreSQL defaults to READ COMMITTED, MySQL and MariaDB default to REPEATABLE READ, SQLite is effectively serialisable, and DuckDB gives snapshot isolation. Application code written against one engine's default can change behaviour silently on another — read-modify-write races that were impossible become possible, or vice versa. Port the isolation assumptions, not just the SQL.

## Axis 3 — query complexity

PostgreSQL has the widest SQL surface here by a distance: lateral joins, materialised and non-materialised CTEs, partial and expression indexes, generated columns, exclusion constraints, window functions that keep gaining features, JSONB with GIN indexes, and an extension mechanism that turned it into a geospatial database, a time-series database and a vector database without forking. If your queries are analytical in shape but transactional in access pattern, this is the engine that will not run out of room.

MySQL and MariaDB trade surface area for a very fast primary-key path and predictable clustered-index behaviour. Most application queries are exactly that shape, which is why so much of the web runs on them. You feel the ceiling when the reporting queries arrive and someone starts writing five-way joins with correlated subqueries.

SQLite's planner is small and honest about it. It handles ordinary plans well, does less well on many-way joins, and has no parallelism — one query, one core. DuckDB inverts every one of these assumptions: vectorised columnar execution, multi-core by default, reads Parquet, CSV, S3 and live PostgreSQL tables directly, and will aggregate a billion rows on a laptop while your OLTP engine is still planning. The right architecture for many teams is not choosing between them but running two: rows in Postgres or SQLite, columns in DuckDB, over the same object storage.

## What this page deliberately leaves out

There is no pricing group, because these engines are free and the money is entirely in who runs them. The comparison people need next — Neon against Supabase against RDS against Aurora, or PlanetScale and Vitess against managed MySQL — is a different page with different fields: cold start, branching, connection pooling, egress, backup retention, region coverage. Hosted-Postgres and hosted-MySQL are planned as their own categories for exactly that reason, and they will have score columns, because those are vendors selling the same thing at different prices.

Until then, the adjacent pages are the useful ones. Convex alternatives covers the layer above this decision, where the database, the API and the sync engine ship together and the engine choice is made for you. S3-compatible storage covers where the blobs go — the other half of every schema on this page, and the substrate DuckDB reads from. LLM APIs covers the retrieval side of the pgvector column, since the embedding model constrains dimensionality and therefore the index you can afford.

## Provenance — every cell, every source

### PostgreSQL {#postgresql}

MVCC relational server with the widest SQL surface and a deep extension ecosystem.

|  |  |
| --- | --- |
| Site | https://www.postgresql.org |
| Docs | https://www.postgresql.org/docs/current/ |
| Repo | https://github.com/postgres/postgres |
| Company | PostgreSQL |
| Founded | 1996 |
| Open source | Yes (PostgreSQL Licence) |
| Profile | https://toolweight.dev/tools/postgresql |

| Field | Value | Confidence | Verified | Source | Note | Anchor |
| --- | --- | --- | --- | --- | --- | --- |
| Embedded or server | Server (client/server) | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/tutorial-arch.html | — | #postgresql-embedded_or_server |
| Concurrency model | MVCC (heap row versions) | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/mvcc-intro.html | Dead row versions live in the heap until vacuumed, which is why bloat is a Postgres word and not a MySQL one. | #postgresql-concurrency_model |
| Write concurrency | Concurrent writers (row-level) | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/explicit-locking.html | — | #postgresql-write_concurrency |
| Isolation levels | Read committed, Repeatable read, Serializable | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/transaction-iso.html | READ UNCOMMITTED is accepted but behaves as READ COMMITTED. SERIALIZABLE is true SSI, not lock-based. | #postgresql-isolation_levels |
| JSON support | Binary JSONB + indexes | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/datatype-json.html | jsonb with GIN indexes, containment operators and SQL/JSON path queries. The reason most document-store migrations get cancelled. | #postgresql-json_support |
| Full-text search | Built-in | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/textsearch.html | tsvector and tsquery with GIN indexes and ranking. Good enough to defer Elasticsearch for a long time; not a replacement for it. | #postgresql-full_text_search |
| Vector search | Extension | Vendor-claimed | 2026-07-01 | https://github.com/pgvector/pgvector | pgvector is the de facto standard: HNSW and IVFFlat indexes, available on essentially every managed Postgres. | #postgresql-vector_search |
| Type strictness | Static, strict | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/typeconv.html | Refuses implicit lossy casts. This is the source of most complaints from people arriving from MySQL, and most of the data-integrity wins. | #postgresql-type_strictness |
| ALTER TABLE | Minimal | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/sql-altertable.html | Near-complete DDL inside a transaction you can roll back. ALTER TYPE still rewrites the table under ACCESS EXCLUSIVE. | #postgresql-alter_table_limits |
| Max database size | — | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/limits.html | Docs state no limit on database size. The per-table ceiling is 32 TB at the default 8 kB page size, and that is the practical single-node wall. | #postgresql-max_db_size |
| Replication | Built-in async + synchronous | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/high-availability.html | Physical streaming plus logical replication in core; synchronous_commit gives quorum or remote-apply durability. Automatic failover is still Patroni's job. | #postgresql-replication |
| PITR | ● | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/continuous-archiving.html | Base backup plus archived WAL restores to a timestamp, an LSN or a named restore point. The reference implementation of the idea. | #postgresql-pitr |
| Online schema change | ◐ | Inferred | 2026-07-01 | — | Many ALTERs are metadata-only and instant; type changes rewrite under an exclusive lock. Teams reach for pgroll or pg_repack, and always set lock_timeout. | #postgresql-online_schema_change |
| Connection model | Process per connection | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/tutorial-arch.html | A backend process per connection. Past a few hundred clients PgBouncer stops being optional, and serverless compute reaches that number fast. | #postgresql-connection_model |
| Default max conns | 100 | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/runtime-config-connection.html | — | #postgresql-default_max_connections |
| Managed options | Neon, Supabase, Amazon RDS, Amazon Aurora, Google Cloud SQL, Azure Database, PlanetScale | Inferred | 2026-07-01 | — | The widest managed market of any engine here, and the reason most teams never actually run Postgres themselves. | #postgresql-hosted_options |
| Ops burden | 4 | Inferred | 2026-07-01 | — | Autovacuum tuning, bloat, transaction-ID wraparound, connection pooling, and major upgrades via pg_upgrade or logical replication. The best engine here is also the most work. | #postgresql-operational_burden |
| Extension ecosystem | 5 | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/docs/current/extend-extensions.html | PostGIS, pgvector, TimescaleDB, pg_cron, pg_stat_statements. Managed hosts each ship a curated subset, which is worth checking before you depend on one. | #postgresql-extension_ecosystem |
| Client libraries | 5 | Inferred | 2026-07-01 | — | — | #postgresql-client_library_maturity |
| Migration tooling | 5 | Inferred | 2026-07-01 | — | Atlas, Flyway, Liquibase, sqlx, Drizzle and Prisma all treat Postgres as the reference target, plus pgroll and reshape for expand/contract rollouts. | #postgresql-migration_tooling |
| GitHub stars | 18,000 | Community-reported | 2026-07-01 | https://github.com/postgres/postgres | Approximate. Official mirror; development happens on the pgsql-hackers mailing list. | #postgresql-github_stars |
| Positioning | The world's most advanced open source relational database. | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/ | — | #postgresql-positioning |
| Licence | PostgreSQL Licence (BSD-style) | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/about/licence/ | — | #postgresql-licence |
| Embed in closed source | ● | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/about/licence/ | Permissive enough to redistribute inside a proprietary product; the engine's shape means almost nobody does. | #postgresql-embedding_freedom |
| Governance | Community project | Vendor-claimed | 2026-07-01 | https://www.postgresql.org/developer/ | A core team and a contributor community with no owning company — the strongest acquisition-risk story on this page. | #postgresql-governance |
| First release | 1997-01-29 | Community-reported | 2026-07-01 | https://www.postgresql.org/docs/current/history.html | PostgreSQL 6.0. The lineage runs back through Postgres95 to Berkeley POSTGRES in 1986. | #postgresql-first_release |

**Verdict.** The strongest engine here on every axis except the one that costs you time. Nothing else combines transactional DDL, this much SQL and pgvector in the same box — and nothing else here needs you to understand autovacuum, bloat and connection pooling before the first incident.

**Pick it when**

- Concurrent writers plus queries that outgrow simple key lookups
- Anything storing embeddings, geometry or time series alongside rows
- Teams who will run it managed, or who have someone who wants to own it

### MariaDB {#mariadb}

GPL-only MySQL fork under a foundation, with Galera clustering and native vectors.

|  |  |
| --- | --- |
| Site | https://mariadb.org |
| Docs | https://mariadb.com/kb/en/documentation/ |
| Repo | https://github.com/MariaDB/server |
| Company | MariaDB Foundation |
| Founded | 2009 |
| Open source | Yes (GPL-2.0) |
| Profile | https://toolweight.dev/tools/mariadb |

| Field | Value | Confidence | Verified | Source | Note | Anchor |
| --- | --- | --- | --- | --- | --- | --- |
| Embedded or server | Both | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/mariadb-embedded-server/ | Primarily a server, but the libmariadbd embedded library still ships — unlike MySQL, which removed its equivalent. | #mariadb-embedded_or_server |
| Concurrency model | MVCC (undo log) | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/innodb/ | InnoDB by default, so the same undo-log versioning as MySQL. Aria and MyISAM behave differently and are not transactional. | #mariadb-concurrency_model |
| Write concurrency | Concurrent writers (row-level) | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/innodb-lock-modes/ | — | #mariadb-write_concurrency |
| Isolation levels | Read uncommitted, Read committed, Repeatable read, Serializable | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/set-transaction/ | Defaults to REPEATABLE READ, matching MySQL. | #mariadb-isolation_levels |
| JSON support | Text functions only | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/json-data-type/ | JSON is an alias for LONGTEXT with a JSON_VALID check constraint. The functions are there; the binary storage and multi-valued indexes are not. | #mariadb-json_support |
| Full-text search | Built-in | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/full-text-indexes/ | FULLTEXT indexes on InnoDB and MyISAM; the Mroonga storage engine is the usual answer for serious CJK search. | #mariadb-full_text_search |
| Vector search | Native type + ANN index | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/vectors/ | A VECTOR type with an HNSW-derived approximate index, GA in the 11.8 LTS release and included in the community server — ahead of MySQL on both counts. | #mariadb-vector_search |
| Type strictness | Static, coercing | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/sql-mode/ | Strict mode has been the default since 10.2.4, but as on MySQL it is a sql_mode setting rather than an engine guarantee. | #mariadb-type_strictness |
| ALTER TABLE | Moderate | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/alter-table/ | ALTER ONLINE and instant ADD COLUMN since 10.3; DDL is not rollback-able inside a transaction. | #mariadb-alter_table_limits |
| Max database size | 64 TB | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/innodb-limitations/ | 64 TiB per InnoDB tablespace at the default page size, inherited from the shared InnoDB lineage. | #mariadb-max_db_size |
| Replication | Built-in async + synchronous | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/galera-cluster/ | Binary-log replication plus Galera synchronous multi-primary clustering bundled since 10.1 — no plugin purchase, no separate product. | #mariadb-replication |
| PITR | ● | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/mariabackup/ | Mariabackup for hot physical backups, plus binlog replay to a point in time. | #mariadb-pitr |
| Online schema change | ● | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/alter-table/ | Native online ALTER, and gh-ost and pt-online-schema-change both work against it. | #mariadb-online_schema_change |
| Connection model | Thread per connection | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/thread-pool-in-mariadb/ | A thread per connection by default, but unlike MySQL the thread pool is in the community server. | #mariadb-connection_model |
| Default max conns | 151 | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/server-system-variables/ | — | #mariadb-default_max_connections |
| Managed options | Amazon RDS, Google Cloud SQL, MariaDB SkySQL | Inferred | 2026-07-01 | — | Thinner than MySQL's. Several hosts advertising MariaDB compatibility are in fact running MySQL. | #mariadb-hosted_options |
| Ops burden | 3 | Inferred | 2026-07-01 | — | Same shape as MySQL. Galera moves it up a point if you run it — synchronous clustering brings flow control and split-brain to think about. | #mariadb-operational_burden |
| Extension ecosystem | 3 | Inferred | 2026-07-01 | — | Pluggable storage engines are a genuine differentiator: ColumnStore, Spider, Mroonga, CONNECT. Not comparable to Postgres extensions in breadth. | #mariadb-extension_ecosystem |
| Client libraries | 4 | Inferred | 2026-07-01 | — | Mostly rides MySQL drivers, which works until it does not — authentication plugins and newer type support are where the divergence shows. | #mariadb-client_library_maturity |
| Migration tooling | 3 | Inferred | 2026-07-01 | — | MySQL tooling generally works, but MariaDB is rarely the tested target, so you find the gaps yourself. | #mariadb-migration_tooling |
| GitHub stars | 6,000 | Community-reported | 2026-07-01 | https://github.com/MariaDB/server | Approximate. Unlike MySQL and Postgres, this is where development actually happens. | #mariadb-github_stars |
| Positioning | The open source relational database, made by the original developers of MySQL. | Vendor-claimed | 2026-07-01 | https://mariadb.org/ | — | #mariadb-positioning |
| Licence | GPL-2.0 | Vendor-claimed | 2026-07-01 | https://mariadb.com/kb/en/mariadb-license/ | — | #mariadb-licence |
| Embed in closed source | ◐ | Inferred | 2026-07-01 | — | The server is GPLv2 with no commercial alternative, so you cannot embed it in closed source. The LGPL client library means you can link a proprietary client — the opposite trade to MySQL's. | #mariadb-embedding_freedom |
| Governance | Foundation | Vendor-claimed | 2026-07-01 | https://mariadb.org/about/ | The MariaDB Foundation stewards the code and guarantees it stays open; MariaDB plc sells products and support around it. | #mariadb-governance |
| First release | 2009-10-29 | Community-reported | 2026-07-01 | https://mariadb.org/about/ | MariaDB 5.1.38 beta, forked from MySQL 5.1 after Oracle's acquisition of Sun. | #mariadb-first_release |

**Verdict.** MySQL without Oracle, and increasingly not just that: Galera clustering in the box and native vector search shipped in the community server before MySQL's did. The cost is a smaller ecosystem and a slow compatibility drift that now genuinely matters when picking drivers and tools.

**Pick it when**

- MySQL-shaped workloads where GPL-only licensing or Oracle stewardship is a blocker
- Synchronous multi-primary clustering without buying anything
- Vector search inside a MySQL dialect you can self-host

### MySQL {#mysql}

The relational server that ran the early web, now Oracle-stewarded and InnoDB-based.

|  |  |
| --- | --- |
| Site | https://www.mysql.com |
| Docs | https://dev.mysql.com/doc/refman/8.4/en/ |
| Repo | https://github.com/mysql/mysql-server |
| Company | Oracle |
| Founded | 1995 |
| Open source | Yes (GPL-2.0 or commercial) |
| Profile | https://toolweight.dev/tools/mysql |

| Field | Value | Confidence | Verified | Source | Note | Anchor |
| --- | --- | --- | --- | --- | --- | --- |
| Embedded or server | Server (client/server) | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/what-is-mysql.html | The libmysqld embedded server library was removed in 8.0; it is a server, full stop. | #mysql-embedded_or_server |
| Concurrency model | MVCC (undo log) | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/innodb-multi-versioning.html | InnoDB keeps old versions in an undo log rather than the heap, so the failure mode is history-list growth, not table bloat. | #mysql-concurrency_model |
| Write concurrency | Concurrent writers (row-level) | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/innodb-locking.html | — | #mysql-write_concurrency |
| Isolation levels | Read uncommitted, Read committed, Repeatable read, Serializable | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html | Defaults to REPEATABLE READ, unlike Postgres. Code ported between the two changes behaviour silently unless you set it explicitly. | #mysql-isolation_levels |
| JSON support | Binary JSON type | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/json.html | A real JSON column type stored in a parsed binary format, with multi-valued indexes over arrays since 8.0.17. | #mysql-json_support |
| Full-text search | Built-in | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/fulltext-search.html | FULLTEXT indexes on InnoDB with natural-language and boolean modes; the ngram parser covers CJK. | #mysql-full_text_search |
| Vector search | Native type | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/9.0/en/vector.html | VECTOR type and distance functions since 9.0, but the approximate index is a HeatWave feature — the community server does exact scans. | #mysql-vector_search |
| Type strictness | Static, coercing | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html | STRICT_TRANS_TABLES is on by default and has been since 5.7, but sql_mode is a runtime variable, so strictness is a configuration fact rather than an engine fact. | #mysql-type_strictness |
| ALTER TABLE | Moderate | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html | Broad ALTER support with INSTANT and INPLACE algorithms. DDL is atomic and crash-safe since 8.0, but you cannot roll it back inside a transaction the way you can on Postgres. | #mysql-alter_table_limits |
| Max database size | 64 TB | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/innodb-limits.html | 64 TiB per InnoDB tablespace at the default 16 kB page size. There is no documented limit on the number of tablespaces. | #mysql-max_db_size |
| Replication | Built-in async + synchronous | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/replication.html | Asynchronous binary-log replication, a semi-synchronous plugin, and Group Replication for quorum writes and automatic failover. | #mysql-replication |
| PITR | ● | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/point-in-time-recovery.html | Full backup plus mysqlbinlog replay to a timestamp or GTID. Percona XtraBackup is the usual hot-backup tool in the open-source world. | #mysql-pitr |
| Online schema change | ● | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl.html | Native online DDL, plus gh-ost and pt-online-schema-change for the cases it cannot do. The strongest story on this page. | #mysql-online_schema_change |
| Connection model | Thread per connection | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/connection-interfaces.html | A thread per connection, so idle connections are far cheaper than on Postgres. A true thread pool is an Enterprise or Percona feature. | #mysql-connection_model |
| Default max conns | 151 | Vendor-claimed | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html | — | #mysql-default_max_connections |
| Managed options | Amazon RDS, Amazon Aurora, Google Cloud SQL, Azure Database, PlanetScale | Inferred | 2026-07-01 | — | — | #mysql-hosted_options |
| Ops burden | 3 | Inferred | 2026-07-01 | — | A server with users, replicas and a binlog to keep an eye on — but no vacuum, and connection handling that forgives a sloppy pool. | #mysql-operational_burden |
| Extension ecosystem | 2 | Inferred | 2026-07-01 | — | A component and plugin API exists, and pluggable storage engines are real, but there is nothing resembling the Postgres extension market. | #mysql-extension_ecosystem |
| Client libraries | 5 | Inferred | 2026-07-01 | — | — | #mysql-client_library_maturity |
| Migration tooling | 4 | Inferred | 2026-07-01 | — | Flyway and Liquibase are first-class, and gh-ost plus pt-online-schema-change are battle-tested at a scale nothing on Postgres matches. | #mysql-migration_tooling |
| GitHub stars | 11,000 | Community-reported | 2026-07-01 | https://github.com/mysql/mysql-server | Approximate. Oracle publishes source drops to this mirror rather than developing in the open. | #mysql-github_stars |
| Positioning | The world's most popular open source database. | Vendor-claimed | 2026-07-01 | https://www.mysql.com/ | — | #mysql-positioning |
| Licence | GPL-2.0 or commercial | Vendor-claimed | 2026-07-01 | https://www.mysql.com/about/legal/licensing/oem/ | — | #mysql-licence |
| Embed in closed source | ○ | Vendor-claimed | 2026-07-01 | https://www.mysql.com/about/legal/licensing/oem/ | GPLv2 unless you buy the commercial licence, which is precisely the product Oracle sells. The client library carries a FOSS Exception, the server does not. | #mysql-embedding_freedom |
| Governance | Single vendor | Vendor-claimed | 2026-07-01 | https://www.mysql.com/about/ | Oracle owns the copyright, the roadmap and the release cadence. MariaDB exists because of this row. | #mysql-governance |
| First release | 1995-05-23 | Community-reported | 2026-07-01 | https://dev.mysql.com/doc/refman/8.4/en/history.html | First internal release; the first widely distributed public binaries followed in 1996. | #mysql-first_release |

**Verdict.** Chosen far less often than it should be for the one thing it is genuinely best at: changing the schema of an enormous table while writes continue. The SQL surface is narrower than Postgres and the extension story is thin, but the operational path is extremely well worn.

**Pick it when**

- Very large tables that must be altered without downtime
- Read-replica topologies your team has already run before
- Environments where the host, ORM or ops runbook already assumes MySQL

### SQLite {#sqlite}

Embedded SQL engine that runs inside your process — a file, not a server.

|  |  |
| --- | --- |
| Site | https://www.sqlite.org |
| Docs | https://www.sqlite.org/docs.html |
| Repo | https://github.com/sqlite/sqlite |
| Company | SQLite |
| Founded | 2000 |
| Open source | Yes (Public domain) |
| Profile | https://toolweight.dev/tools/sqlite |

| Field | Value | Confidence | Verified | Source | Note | Anchor |
| --- | --- | --- | --- | --- | --- | --- |
| Embedded or server | Embedded (in-process) | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/about.html | There is a client/server wrapper in the wild, but the engine itself is a library. | #sqlite-embedded_or_server |
| Concurrency model | Reader/writer locking | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/lockingv3.html | WAL mode lets readers proceed against a snapshot while one writer appends, which is MVCC-like but still one writer. | #sqlite-concurrency_model |
| Write concurrency | Single writer | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/wal.html | One write transaction per database at a time; others get SQLITE_BUSY until the busy timeout expires. | #sqlite-write_concurrency |
| Isolation levels | Serializable | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/isolation.html | Serialisable by default. READ UNCOMMITTED exists only between connections sharing a cache. | #sqlite-isolation_levels |
| JSON support | Text functions only | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/json1.html | JSON functions built in since 3.38 and a binary JSONB representation since 3.45, but no JSON column type; index with expression indexes. | #sqlite-json_support |
| Full-text search | Extension | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/fts5.html | FTS5 is a loadable extension but ships in the amalgamation and is compiled into most distributions. | #sqlite-full_text_search |
| Vector search | Extension | Community-reported | 2026-07-01 | https://github.com/asg017/sqlite-vec | sqlite-vec gives a vector type and brute-force KNN. No approximate index, so recall is exact and cost is linear. | #sqlite-vector_search |
| Type strictness | Dynamic (per-value) | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/datatype3.html | Type affinity, not enforcement. STRICT tables since 3.37 give you real checking if you opt in per table. | #sqlite-type_strictness |
| ALTER TABLE | Severe (rebuild required) | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/lang_altertable.html | ADD COLUMN, DROP COLUMN (3.35+), RENAME only. Changing a type or adding a constraint means the documented twelve-step rebuild. | #sqlite-alter_table_limits |
| Max database size | 256 TB | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/limits.html | 256 TiB is the format limit. The practical wall is backup and single-writer throughput, which most teams meet long before 1 TB. | #sqlite-max_db_size |
| Replication | Third-party only | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/whentouse.html | Nothing in the engine. Litestream, LiteFS, rqlite and Turso each solve it differently and none is free of trade-offs. | #sqlite-replication |
| PITR | ◐ | Community-reported | 2026-07-01 | https://litestream.io/how-it-works/ | Litestream ships WAL frames to object storage continuously, giving real PITR — but it is a separate process you must run and monitor. | #sqlite-pitr |
| Online schema change | ○ | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/lang_altertable.html | A rebuild holds the write lock for its duration; on a large table that is user-visible downtime. | #sqlite-online_schema_change |
| Connection model | In-process (no connections) | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/threadsafe.html | — | #sqlite-connection_model |
| Default max conns | — | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/whentouse.html | Not applicable — the database is a file your process opens. | #sqlite-default_max_connections |
| Managed options | Turso, Cloudflare D1, Fly.io LiteFS | Inferred | 2026-07-01 | — | All three are SQLite-compatible services rather than managed SQLite; D1 and Turso add their own replication layers. | #sqlite-hosted_options |
| Ops burden | 1 | Inferred | 2026-07-01 | — | No daemon, no users, no upgrades in place. Add one point in practice if you adopt Litestream and actually test the restore. | #sqlite-operational_burden |
| Extension ecosystem | 4 | Inferred | 2026-07-01 | — | A stable loadable-extension ABI with FTS5, R-Tree, sqlite-vec and sqlean, but no package manager and no host that curates them. | #sqlite-extension_ecosystem |
| Client libraries | 5 | Inferred | 2026-07-01 | — | — | #sqlite-client_library_maturity |
| Migration tooling | 3 | Inferred | 2026-07-01 | — | Atlas, Drizzle and Alembic automate the rebuild dance, but the dance is still happening underneath. | #sqlite-migration_tooling |
| GitHub stars | 8,000 | Community-reported | 2026-07-01 | https://github.com/sqlite/sqlite | Approximate. Read-only mirror; development happens in Fossil, so this measures visibility only. | #sqlite-github_stars |
| Positioning | Small. Fast. Reliable. Choose any three. | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/ | — | #sqlite-positioning |
| Licence | Public domain | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/copyright.html | — | #sqlite-licence |
| Embed in closed source | ● | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/copyright.html | Public domain. A paid licence exists purely so companies in jurisdictions without a public domain can have a signed document. | #sqlite-embedding_freedom |
| Governance | Independent team | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/consortium.html | Hwaci employs the core developers; the SQLite Consortium funds them without steering the roadmap. | #sqlite-governance |
| First release | 2000-08-17 | Vendor-claimed | 2026-07-01 | https://www.sqlite.org/chronology.html | — | #sqlite-first_release |

**Verdict.** The best answer for any workload where one process owns the data, and the answer most teams reject for reasons that stopped being true a decade ago. The real constraints are the single writer, the absent replication story and the table rebuild you need for most schema changes — none of which is throughput.

**Pick it when**

- One application process, or one machine, owning the data
- Read-heavy workloads where removing the network hop is the whole win
- Anything shipped to the edge, a device, a CLI or a test suite

### DuckDB {#duckdb}

In-process columnar analytics engine — SQLite's shape, a warehouse's execution model.

|  |  |
| --- | --- |
| Site | https://duckdb.org |
| Docs | https://duckdb.org/docs/ |
| Repo | https://github.com/duckdb/duckdb |
| Company | DuckDB Labs |
| Founded | 2019 |
| Open source | Yes (MIT) |
| Profile | https://toolweight.dev/tools/duckdb |

| Field | Value | Confidence | Verified | Source | Note | Anchor |
| --- | --- | --- | --- | --- | --- | --- |
| Embedded or server | Embedded (in-process) | Vendor-claimed | 2026-07-01 | https://duckdb.org/why_duckdb | — | #duckdb-embedded_or_server |
| Concurrency model | MVCC (single process) | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/connect/concurrency | Optimistic MVCC within one process. A second process cannot open the same file read-write. | #duckdb-concurrency_model |
| Write concurrency | Single writer | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/connect/concurrency | One process holds the write lock on the database file; concurrent transactions inside it are serialised optimistically and conflicts abort. | #duckdb-write_concurrency |
| Isolation levels | Snapshot | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/connect/concurrency | Snapshot isolation rather than the ANSI ladder; the SQL syntax for setting levels is largely absent. | #duckdb-isolation_levels |
| JSON support | Text functions only | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/data/json/overview | The json extension gives a JSON logical type backed by text. Native STRUCT, LIST and MAP types are usually the better answer. | #duckdb-json_support |
| Full-text search | Extension | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/extensions/full_text_search | The fts extension gives BM25 scoring. Adequate for filtering a dataset, not for powering a search box. | #duckdb-full_text_search |
| Vector search | Extension | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/extensions/vss | The vss extension adds an HNSW index; persistence of that index has carried experimental caveats, so treat it as analysis rather than serving. | #duckdb-vector_search |
| Type strictness | Static, strict | Inferred | 2026-07-01 | — | Types are enforced and out-of-range casts error, though CSV and JSON ingestion infers liberally by design. | #duckdb-type_strictness |
| ALTER TABLE | Moderate | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/sql/statements/alter_table | ADD, DROP, RENAME and type changes, all inside a transaction — but the supported set is narrower than the server engines'. | #duckdb-alter_table_limits |
| Max database size | — | Unknown | — | — | No documented format ceiling. In practice bounded by local disk and by the single-process write path. | #duckdb-max_db_size |
| Replication | None | Vendor-claimed | 2026-07-01 | https://duckdb.org/why_duckdb | By design. Distribution is MotherDuck's product, not the engine's. | #duckdb-replication |
| PITR | ○ | Inferred | 2026-07-01 | — | No WAL archiving or log shipping. Recovery means re-running the pipeline that built the file, which is often the right model anyway. | #duckdb-pitr |
| Online schema change | ○ | Inferred | 2026-07-01 | — | — | #duckdb-online_schema_change |
| Connection model | In-process (no connections) | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/connect/concurrency | — | #duckdb-connection_model |
| Default max conns | — | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/connect/concurrency | Not applicable — connections are objects inside your process. | #duckdb-default_max_connections |
| Managed options | MotherDuck | Inferred | 2026-07-01 | — | MotherDuck is the only serious managed offering, and it extends DuckDB rather than merely hosting it. | #duckdb-hosted_options |
| Ops burden | 1 | Inferred | 2026-07-01 | — | Nothing to run. The burden moves upstream into whatever pipeline produces the data, which the score does not capture. | #duckdb-operational_burden |
| Extension ecosystem | 4 | Vendor-claimed | 2026-07-01 | https://duckdb.org/docs/stable/extensions/overview | INSTALL and LOAD from a first-party repository, plus a community-extensions channel. Young, but the distribution mechanism is better than SQLite's. | #duckdb-extension_ecosystem |
| Client libraries | 3 | Inferred | 2026-07-01 | — | Excellent Python, Node, Java, Go and Rust clients. ORM and query-builder coverage is thin because nobody builds CRUD apps on it. | #duckdb-client_library_maturity |
| Migration tooling | 2 | Inferred | 2026-07-01 | — | Migrations are barely a concept here — most DuckDB files are rebuilt rather than migrated. | #duckdb-migration_tooling |
| GitHub stars | 33,000 | Community-reported | 2026-07-01 | https://github.com/duckdb/duckdb | Approximate. The only project here whose star count reflects genuine recent momentum rather than a mirror's visibility. | #duckdb-github_stars |
| Positioning | DuckDB is a fast in-process analytical database. | Vendor-claimed | 2026-07-01 | https://duckdb.org/ | — | #duckdb-positioning |
| Licence | MIT | Vendor-claimed | 2026-07-01 | https://github.com/duckdb/duckdb/blob/main/LICENSE | — | #duckdb-licence |
| Embed in closed source | ● | Vendor-claimed | 2026-07-01 | https://github.com/duckdb/duckdb/blob/main/LICENSE | — | #duckdb-embedding_freedom |
| Governance | Foundation | Vendor-claimed | 2026-07-01 | https://duckdb.org/foundation/ | The non-profit DuckDB Foundation holds the IP specifically so DuckDB Labs and MotherDuck cannot close it. | #duckdb-governance |
| First release | 2019-06-26 | Community-reported | 2026-07-01 | https://duckdb.org/why_duckdb | Version 0.1.0. The project began at CWI Amsterdam in 2018. | #duckdb-first_release |

**Verdict.** The analytical contrast, included so the other four are legible — not a candidate for your application database. It answers questions the OLTP engines answer badly, on a laptop, over Parquet you never loaded, and it will lose your data if you treat it as a system of record without a backup story.

**Pick it when**

- Aggregation and scans over columns rather than fetching rows by key
- Querying Parquet, CSV or object storage without an ingestion pipeline
- The reporting half of a system whose rows live in Postgres or SQLite

## Methodology

Every cell here comes from the engine's own reference manual rather than a vendor pricing page, which is why this is the best-sourced page on toolweight: these projects document their limits precisely and change them slowly. Where a claim is a judgement rather than a documented fact — extension ecosystem, migration tooling, client-library maturity, and the operational burden score — it is marked inferred and the ladder is spelled out in the column help so you can disagree with the placement rather than the number. Where a project genuinely documents no limit, the cell is null and renders as an em dash instead of a fabricated ceiling.

The killer field is operational burden, scored 1–5 where lower is better. It measures what a competent team must do to keep the engine healthy in production, not how hard it is to install: 1 is a file your process opens, 5 is a cluster with a full-time owner. It is the field that inverts the usual ranking — PostgreSQL has the strongest feature set on this page and the highest burden, and pretending otherwise is how teams end up with a vacuum problem eighteen months in. One finding is visible only by absence: SQLite appears nowhere in the timeline below. It ships several releases a year, all backwards compatible, and none of them change a decision. That stability is a feature and it does not generate news.

## FAQ

### Is SQLite production-ready for a real web application?

Yes, with conditions. Turn on WAL mode, set a busy timeout, keep write transactions short, and adopt a replication or backup tool such as Litestream on day one rather than after the first disk failure. The limits that bite are single-writer serialisation and the lack of built-in replication — not throughput, correctness or size. SQLite is more tested than almost any code you will ship alongside it.

### When does SQLite's single writer actually become a problem?

Multiply your write transaction duration by your write rate. Five-millisecond transactions at 200 writes per second use about a second of writer time per second of wall clock, and you are already near the wall. Long transactions are the real killer: one 300 ms write blocks every other writer for 300 ms. If you cannot bound transaction duration, you want an MVCC engine.

### MySQL or MariaDB in 2026?

For a normal application either works and the drivers are largely interchangeable. Choose MariaDB if you want a foundation rather than Oracle, GPLv2 without a commercial upsell, native vector search in the community server, or Galera clustering in the box. Choose MySQL if your managed host, ORM or replication tooling assumes it, or if you need Oracle's commercial licence to embed the server in a product.

### Do I need a dedicated vector database, or is pgvector enough?

For almost everyone pgvector is enough. It gives you HNSW and IVFFlat indexes inside the same transaction as your rows, so embeddings cannot drift out of sync with the records they describe. Reach for something specialised only when index build time, memory-resident recall at very high dimensionality, or billion-scale corpora become the bottleneck — which is later than most teams assume.

### Can DuckDB be my application database?

No, and it does not try to be. DuckDB is an in-process columnar engine built for scans and aggregation, with a single-process write path and no replication or point-in-time recovery. It is superb as the analytics half of a system — querying Parquet on object storage, or reading straight from your Postgres — and a poor fit for many clients writing single rows.

### Is PostgreSQL always the safe default?

It is the safest default, not a free one. You get the widest SQL surface, transactional DDL and the deepest extension ecosystem; you also get autovacuum, bloat, transaction-ID wraparound and a process per connection. If nobody on the team will own those, use managed Postgres or pick a lighter engine deliberately rather than discovering the burden during an incident.

### How painful are schema migrations on each engine?

MySQL and MariaDB are best: online DDL plus gh-ost and pt-online-schema-change make altering a huge table routine. PostgreSQL runs DDL inside a transaction, which is a genuine advantage, but type changes rewrite the table under an exclusive lock, so teams reach for pgroll or pg_repack. SQLite is worst: most changes require the documented twelve-step table rebuild, though modern tooling automates it.

## Recent changes

| Date | Kind | Event | Tools | Source |
| --- | --- | --- | --- | --- |
| 2025-06-04 | launch | **MariaDB 11.8 LTS ships vector search in the community server** — A VECTOR column type with an approximate nearest-neighbour index reaches GA in a mainstream open-source relational engine, without an enterprise tier. It landed ahead of MySQL, whose 9.x VECTOR type still leans on HeatWave for approximate indexing, and it narrows one of pgvector's few remaining structural advantages. | mariadb, mysql, postgresql | https://mariadb.com/kb/en/vectors/ |
| 2025-09-16 | launch | **DuckDB 1.4.0 becomes the first LTS release** — DuckDB adopts a long-term-support line and adds database encryption and MERGE INTO. The LTS commitment is the more consequential half: it is the point at which running DuckDB as durable infrastructure, rather than as a notebook tool, stops being reckless. | duckdb | https://duckdb.org/docs/stable/ |
| 2025-09-25 | launch | **PostgreSQL 18 released** — An asynchronous I/O subsystem, uuidv7() in core, skip scan for multi-column B-tree indexes, virtual generated columns, and — quietly the most useful item — planner statistics that survive pg_upgrade, removing the post-upgrade ANALYZE window during which a freshly migrated cluster plans badly. | postgresql | https://www.postgresql.org/docs/18/release-18.html |
| 2025-05-14 | funding | **Databricks acquires Neon** — Serverless Postgres gets absorbed into a data-platform vendor at roughly a billion dollars, on the stated thesis that agents create databases faster than humans do. Read it as confirmation that the money in this category is entirely in who operates the engine, which is why this page has no pricing column. | postgresql | — |
| 2026-04-30 | deprecation | **MySQL 8.0 leaves premier support** — Oracle's lifetime support policy moves 8.0 out of premier support eight years after GA, leaving 8.4 as the supported LTS line and the 9.x innovation releases as the fast lane. Teams still on 8.0 now have a scheduled upgrade rather than an optional one. | mysql | https://www.oracle.com/support/lifetime-support/ |

## Sources

| Source | Last verified |
| --- | --- |
| https://www.sqlite.org/about.html | 2026-07-01 |
| https://www.sqlite.org/lockingv3.html | 2026-07-01 |
| https://www.sqlite.org/wal.html | 2026-07-01 |
| https://www.sqlite.org/isolation.html | 2026-07-01 |
| https://www.sqlite.org/json1.html | 2026-07-01 |
| https://www.sqlite.org/fts5.html | 2026-07-01 |
| https://github.com/asg017/sqlite-vec | 2026-07-01 |
| https://www.sqlite.org/datatype3.html | 2026-07-01 |
| https://www.sqlite.org/lang_altertable.html | 2026-07-01 |
| https://www.sqlite.org/limits.html | 2026-07-01 |
| https://www.sqlite.org/whentouse.html | 2026-07-01 |
| https://litestream.io/how-it-works/ | 2026-07-01 |
| https://www.sqlite.org/threadsafe.html | 2026-07-01 |
| https://github.com/sqlite/sqlite | 2026-07-01 |
| https://www.sqlite.org/ | 2026-07-01 |
| https://www.sqlite.org/copyright.html | 2026-07-01 |
| https://www.sqlite.org/consortium.html | 2026-07-01 |
| https://www.sqlite.org/chronology.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/tutorial-arch.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/mvcc-intro.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/explicit-locking.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/transaction-iso.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/datatype-json.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/textsearch.html | 2026-07-01 |
| https://github.com/pgvector/pgvector | 2026-07-01 |
| https://www.postgresql.org/docs/current/typeconv.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/sql-altertable.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/limits.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/high-availability.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/continuous-archiving.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/runtime-config-connection.html | 2026-07-01 |
| https://www.postgresql.org/docs/current/extend-extensions.html | 2026-07-01 |
| https://github.com/postgres/postgres | 2026-07-01 |
| https://www.postgresql.org/ | 2026-07-01 |
| https://www.postgresql.org/about/licence/ | 2026-07-01 |
| https://www.postgresql.org/developer/ | 2026-07-01 |
| https://www.postgresql.org/docs/current/history.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/what-is-mysql.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/innodb-multi-versioning.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/innodb-locking.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/json.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/fulltext-search.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/9.0/en/vector.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/innodb-limits.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/replication.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/point-in-time-recovery.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/connection-interfaces.html | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html | 2026-07-01 |
| https://github.com/mysql/mysql-server | 2026-07-01 |
| https://www.mysql.com/ | 2026-07-01 |
| https://www.mysql.com/about/legal/licensing/oem/ | 2026-07-01 |
| https://www.mysql.com/about/ | 2026-07-01 |
| https://dev.mysql.com/doc/refman/8.4/en/history.html | 2026-07-01 |
| https://mariadb.com/kb/en/mariadb-embedded-server/ | 2026-07-01 |
| https://mariadb.com/kb/en/innodb/ | 2026-07-01 |
| https://mariadb.com/kb/en/innodb-lock-modes/ | 2026-07-01 |
| https://mariadb.com/kb/en/set-transaction/ | 2026-07-01 |
| https://mariadb.com/kb/en/json-data-type/ | 2026-07-01 |
| https://mariadb.com/kb/en/full-text-indexes/ | 2026-07-01 |
| https://mariadb.com/kb/en/vectors/ | 2026-07-01 |
| https://mariadb.com/kb/en/sql-mode/ | 2026-07-01 |
| https://mariadb.com/kb/en/alter-table/ | 2026-07-01 |
| https://mariadb.com/kb/en/innodb-limitations/ | 2026-07-01 |
| https://mariadb.com/kb/en/galera-cluster/ | 2026-07-01 |
| https://mariadb.com/kb/en/mariabackup/ | 2026-07-01 |
| https://mariadb.com/kb/en/thread-pool-in-mariadb/ | 2026-07-01 |
| https://mariadb.com/kb/en/server-system-variables/ | 2026-07-01 |
| https://github.com/MariaDB/server | 2026-07-01 |
| https://mariadb.org/ | 2026-07-01 |
| https://mariadb.com/kb/en/mariadb-license/ | 2026-07-01 |
| https://mariadb.org/about/ | 2026-07-01 |
| https://duckdb.org/why_duckdb | 2026-07-01 |
| https://duckdb.org/docs/stable/connect/concurrency | 2026-07-01 |
| https://duckdb.org/docs/stable/data/json/overview | 2026-07-01 |
| https://duckdb.org/docs/stable/extensions/full_text_search | 2026-07-01 |
| https://duckdb.org/docs/stable/extensions/vss | 2026-07-01 |
| https://duckdb.org/docs/stable/sql/statements/alter_table | 2026-07-01 |
| https://duckdb.org/docs/stable/extensions/overview | 2026-07-01 |
| https://github.com/duckdb/duckdb | 2026-07-01 |
| https://duckdb.org/ | 2026-07-01 |
| https://github.com/duckdb/duckdb/blob/main/LICENSE | 2026-07-01 |
| https://duckdb.org/foundation/ | 2026-07-01 |

## Related comparisons

- [Convex alternatives](https://toolweight.dev/compare/convex-alternatives) — What are the best alternatives to Convex, and how hard is each one to leave?
- [S3-compatible storage](https://toolweight.dev/compare/s3-compatible-storage) — Which S3-compatible object storage provider is actually cheapest once egress is counted?
- [Vercel alternatives](https://toolweight.dev/compare/vercel-alternatives) — Which Vercel alternative should I use, and what happens to my bill if my site goes viral?
- [LLM APIs](https://toolweight.dev/compare/llm-apis) — Which frontier LLM API should I build on?

## Licence and attribution

Data from toolweight (https://toolweight.dev), licensed CC-BY-4.0.

- Licence: [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)
- Canonical HTML: https://toolweight.dev/compare/sqlite-vs-postgres-vs-mysql
- Machine-readable: https://toolweight.dev/compare/sqlite-vs-postgres-vs-mysql.md · https://toolweight.dev/api/v1 · https://toolweight.dev/mcp
- toolweight takes no affiliate revenue and sells no placements. Corrections: https://toolweight.dev/suggest
