There is no "best database" in the abstract. For most websites and business applications, MySQL, PostgreSQL and SQLite are all perfectly capable, and the real difference lies in your circumstances. The quick version: if you are on shared hosting or your platform (WordPress, say) is built around MySQL, use MySQL. If you are starting a new project on your own server with complex data, heavy reporting or lots of JSON, use PostgreSQL. If the app is small, runs on a single server and doesn't do much concurrent writing, SQLite is probably enough, and it is the simplest of the three.
MySQL is a widely used open-source relational database that has powered a large share of the web since the 1990s; MariaDB is a compatible fork of it. PostgreSQL is another open-source relational database, known for strict adherence to the SQL standard, rich data types and extensibility. SQLite isn't a server at all: it is a library that keeps the whole database in a single file and runs inside your application process. Below, the three are compared on the points that actually change the decision in practice.
Short answer: For most websites, MySQL, PostgreSQL and SQLite are all good enough, and the right choice depends on your situation: MySQL for shared hosting and WordPress, PostgreSQL for a new project on your own server with complex data, reporting or heavy JSON use, and SQLite for a small app on a single server without much concurrent writing. If your team only knows one of them, that is usually the right pick.
What each one is good at
MySQL
- It's everywhere. Practically every shared host, control panel and tutorial defaults to MySQL or MariaDB.
- The PHP ecosystem grew up on it. WordPress, WooCommerce and most PHP CMSs are built for it.
- Easy to get started. The defaults are sensible for typical web workloads, and documentation and experienced people are easy to find.
- Mature replication. Setting up read-only replicas to spread read load is a well-trodden path.
PostgreSQL
- Rich data types:
jsonb, arrays, ranges,uuid,inetand user-defined types. - More powerful SQL for complex queries: CTEs, window functions, partial indexes and expression indexes.
- Extensions: PostGIS for geospatial data and
pg_trgmfor fuzzy text search, for example. - Strictness: it generally rejects invalid data instead of silently coercing it, which prevents corrupted data in the long run.
- Transactional DDL: schema changes (migrations) run inside a transaction, so if one fails halfway through, it rolls back completely.
SQLite
- Zero maintenance: no service, no users, no port. The database is a file.
- Simple backups:
.backuporVACUUM INTOgives you a consistent copy. - Fast reads: queries run in the same process, so there is no network round trip.
- Great for testing and development: which is why Laravel 11 and later default to SQLite for new projects.
Concurrency: where the real difference is
This is the most important technical difference when choosing.
MySQL (with InnoDB) and PostgreSQL both use MVCC: readers don't wait for writers, and locking happens at the row level. Both are designed for hundreds of concurrent connections reading and writing.
One operational difference: PostgreSQL forks a separate process per connection, so connections are relatively expensive. With many app instances or workers, you typically put a connection pooler such as PgBouncer in front of it. MySQL uses a thread per connection and copes more comfortably with high connection counts.
SQLite accepts only one writer at a time. In WAL mode, readers keep working alongside that writer without being blocked. To make this work well, two settings are almost always needed:
PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
busy_timeout tells SQLite to wait up to 5 seconds when the database is busy writing, instead of failing immediately with database is locked. In Laravel you can set these for the sqlite connection in config/database.php.
SQLite writes are usually very short, so "one writer at a time" isn't a problem for most small and medium sites. It becomes one when you have long-running write transactions or several servers need to write to the same database.
JSON support
All three can store and query JSON, but not at the same level:
- PostgreSQL: the
jsonbtype stores data in a parsed binary format, and you can put a GIN index on the whole document, so queries on arbitrary keys inside the JSON are fast. If a significant part of your data is semi-structured, this is the strongest option. - MySQL: has a
JSONtype and a full set of functions to read and modify it. To index it, you usually create a generated column from the path you care about and index that. It works, but you need to know in advance which keys you'll search on. - SQLite: JSON functions (such as
json_extract) are built in on recent versions, and an expression index can speed up frequently used keys.
In Laravel, all three work with the same where('options->theme', 'dark') syntax; the only difference is performance and index type.
Maintenance overhead
| MySQL | PostgreSQL | SQLite | |
|---|---|---|---|
| Separate service | Yes | Yes | No |
| User and permission management | Required | Required | File permissions only |
| Major version upgrades | Usually simple | Needs pg_upgrade or dump and restore |
Update the library |
| Routine maintenance | Little | autovacuum is automatic, but you should know how to check it's healthy | Occasional VACUUM |
| Backups | mysqldump |
pg_dump |
Consistent copy of the file |
Every database service is one more thing to keep updated, secured and backed up. For backing up any of the three properly, see The 3-2-1 backup rule in practice.
Hosting
- Shared hosting: almost always MySQL or MariaDB. Many shared hosts don't offer PostgreSQL. SQLite usually works, since it's just a file.
- VPS: all three are available and install with
apton Ubuntu 24.04. The difference between shared hosting and a VPS is covered in VPS vs. shared hosting. - Docker: there are official MySQL and PostgreSQL images, and running one next to your app with Docker Compose is straightforward.
- Managed services: the major cloud providers generally offer both MySQL and PostgreSQL as managed services.
When SQLite is genuinely enough
Many people think of SQLite as "just for testing", but it is a serious choice when:
- The app runs on a single server, and multiple servers won't connect to the same database.
- Write load is low to moderate: a blog, a company site, an internal dashboard, a small team tool.
- The data is a few gigabytes, not terabytes.
- You don't want to maintain a separate service.
Signs it's time to move to MySQL or PostgreSQL:
- Several app servers or containers need to write to the same database.
database is lockederrors keep coming back despite WAL andbusy_timeout.- You need replication, network access from reporting tools, or separate users with different privileges.
When NoSQL makes sense
NoSQL databases such as MongoDB or Redis aren't general-purpose replacements for a relational database; they are tools for specific problems:
- Redis for caching, queues, sessions and counters. Usually alongside your main database, not instead of it. See Caching in Laravel and Queues in Laravel for examples.
- Document databases (such as MongoDB) when the shape of your data genuinely varies from record to record and there aren't many relationships between records.
- Time-series or search databases (such as Elasticsearch or OpenSearch) for logs, metrics and full-text search at scale.
If your data is users, orders, invoices and products, things that relate to each other, a relational database is almost always the better choice. PostgreSQL's jsonb also covers much of the need for "NoSQL flexibility".
Decision table
| Your situation | Recommended choice |
|---|---|
| Shared hosting | MySQL / MariaDB |
| WordPress or another MySQL-based CMS | MySQL / MariaDB |
| New project on a VPS with relational data and reporting | PostgreSQL |
| Lots of JSON data you need to query | PostgreSQL |
| Geospatial data | PostgreSQL + PostGIS |
| Small site or internal tool on one server | SQLite |
| Desktop or mobile app | SQLite |
| Multiple app servers writing concurrently | MySQL or PostgreSQL |
| Your team only knows one of them | That one |
| Cache, queues, sessions | Redis, alongside your main database |
Frequently asked questions
What is the difference between MySQL and PostgreSQL?
Both are open-source relational databases with MVCC and row-level locking, and both handle hundreds of concurrent connections. PostgreSQL has richer data types such as jsonb, more powerful SQL for complex queries and transactional DDL; MySQL is more common on shared hosting and in the PHP ecosystem, and copes more easily with very high connection counts.
What is the difference between MySQL and MariaDB?
MariaDB is a fork of MySQL that has stayed compatible with it and is shipped in place of MySQL by many hosts and Linux distributions. For typical web workloads such as WordPress there is no noticeable difference, although the two have gradually diverged in newer features.
Is SQLite good enough for a production website?
Yes, if the app runs on a single server, write load is low to moderate and the data is a few gigabytes. With WAL mode enabled and busy_timeout set, it is a serious, low-maintenance choice for blogs, company sites and internal dashboards.
What does "database is locked" mean in SQLite?
It means a connection tried to write while another writer was busy, because SQLite only accepts one writer at a time. Enabling WAL mode and setting busy_timeout usually fixes it; if it keeps happening, it is time to move to MySQL or PostgreSQL.
Is MongoDB better than MySQL?
For data such as users, orders, invoices and products that relate to each other, a relational database is almost always the better choice. MongoDB makes sense when the structure of your data genuinely varies from record to record and there are few relationships between records.
Wrap-up
Choosing between MySQL, PostgreSQL and SQLite matters less than it seems, especially if you use an ORM such as Eloquent. MySQL for compatibility and availability, PostgreSQL for powerful SQL and complex data, SQLite for simplicity when the app lives on one server. Start with what your team knows and your host supports, back up your data properly from day one, and save a database migration for the day you hit a real limit, not a hypothetical one.