Two Different Shapes of Database
SQLite and MySQL both speak SQL and both store rows in tables, but the way they fit into a system is completely different. SQLite is a library — your application links against it and reads from a file on disk. MySQL is a server — a separate process you connect to over a socket or network.
That single distinction shapes everything else: how you install them, how many writers can work at once, how you back things up, how you deploy. Most of the questions people ask about SQLite vs MySQL are really questions about embedded vs client-server.
-- SQLite: open a file, you have a database.
sqlite3 app.db
-- MySQL: connect to a running server.
mysql -h localhost -u root -p
The SQLite command opens (or creates) a file. The MySQL command opens a connection to a process that has to already be running, configured, and accepting logins.
Architecture: Embedded vs Client-Server
In a SQLite app, the database engine runs inside your program. There's no port, no daemon, no systemctl start. A sqlite3 library call reads and writes pages directly from a file on disk.
MySQL is the opposite. The mysqld server holds the data, manages connections, enforces permissions, runs the query planner, and handles locking. Your app is a client that sends SQL strings over the wire and receives result rows back.
The practical consequences:
- Deployment. SQLite ships with your app — one binary, one file. MySQL needs a separate server to install, secure, monitor, and back up.
- Network access. MySQL exposes a port, so multiple application servers can connect to the same database. SQLite assumes one process (or a few cooperating processes) on the same machine.
- Permissions. MySQL has users, roles, and
GRANTstatements. SQLite's only permission system is the OS file permissions on the database file.
Neither shape is "better." They solve different problems.
Concurrency and Writes
This is where the two really diverge. MySQL's InnoDB engine does row-level locking — many connections can write to different rows at the same time without blocking each other.
SQLite serializes writes at the database level. Only one writer at a time, full stop. Readers can run alongside the writer (especially in WAL mode), but a second writer waits its turn.
-- SQLite: this works fine for many readers, one writer at a time.
PRAGMA journal_mode = WAL;
-- MySQL: many writers, fine-grained locking.
-- (No special setup — InnoDB does it by default.)
For an app with one or two processes doing modest writes — a desktop tool, a mobile app, a small CMS — SQLite's serialized writes are usually fast enough that you'd never notice. For a busy web service with hundreds of connections all inserting orders or updating sessions, MySQL's row-level locking is the difference between "fine" and "everything is queued behind one lock."
Data Types
MySQL has a long, strict list of types: TINYINT, INT, BIGINT, VARCHAR(n), DATETIME, DECIMAL(p,s), BLOB, JSON, and many more. Declare a column INT and MySQL will reject a string.
SQLite uses type affinity instead. Column types are hints, not enforced rules. You can put a string in an INTEGER column and SQLite will store it (unless you opt into STRICT tables, added in version 3.37).
Both rows insert successfully. The flexibility is convenient when prototyping, surprising when you expect database-level type safety. Use STRICT tables when you want MySQL-style enforcement in SQLite.
Syntax Differences You'll Actually Hit
Most basic SQL — SELECT, JOIN, WHERE, GROUP BY — is identical. The differences cluster around a few areas:
- Auto-increment primary keys. SQLite uses
INTEGER PRIMARY KEY(which auto-increments by default). MySQL usesINT AUTO_INCREMENT PRIMARY KEY. - String quoting. MySQL allows backticks for identifiers (
`table`). SQLite uses double quotes ("table") per the SQL standard. - Date functions. MySQL has
NOW(),CURDATE(),DATE_ADD(). SQLite hasdatetime('now'),date('now'),datetime('now', '+1 day'). LIMITsyntax. Both supportLIMIT n OFFSET m, so this one's compatible.- Booleans. MySQL has
BOOLEAN(an alias forTINYINT(1)). SQLite stores booleans as0and1inINTEGERcolumns.
-- MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME DEFAULT NOW()
);
-- SQLite
CREATE TABLE users (
id INTEGER PRIMARY KEY,
created_at TEXT DEFAULT (datetime('now'))
);
Same intent, different keywords. The mental model carries over; the syntax needs a small adjustment.
Performance: It Depends on the Question
"Is SQLite faster than MySQL?" doesn't have one answer.
For a single process doing local reads and writes, SQLite is often faster — there's no network hop, no inter-process communication, no query parser running in a separate address space. A SELECT in SQLite is essentially a function call.
For many concurrent connections writing to the same database, MySQL pulls ahead because of row-level locking. SQLite's single-writer model means contention shows up fast under that workload.
For read-heavy workloads with WAL mode enabled, SQLite scales surprisingly well — readers don't block each other or the single writer. Plenty of production sites serve real traffic from SQLite.
Don't pick based on benchmarks you read online. Pick based on your actual access pattern.
When Each One Is the Right Choice
Reach for SQLite when:
- The database lives next to one application (mobile app, desktop tool, CLI, small website).
- You want zero-configuration deployment — just ship the file.
- Reads heavily outnumber writes, or writes are infrequent.
- You need an embedded test database that mirrors production SQL.
- You're prototyping and don't want to think about a server yet.
Reach for MySQL when:
- Multiple application servers need to share one database.
- You have lots of concurrent writers.
- You need fine-grained user permissions and role management.
- You're building on a stack (LAMP, common managed cloud setups) that expects MySQL.
- Operational tooling — replication, point-in-time recovery, monitoring — is a hard requirement.
A rough heuristic: if you'd describe your storage needs as "one app, one disk," SQLite is probably enough. If you'd say "a service, with operators," reach for MySQL (or PostgreSQL).
Migrating Between Them
Starting on SQLite and moving to MySQL later is a well-trodden path — and a fine plan. The schemas translate with small adjustments, and the data exports cleanly via .dump from the SQLite CLI. You'll mostly be fixing up auto-increment syntax, date functions, and any SQLite-specific features (partial indexes with strange shapes, WITHOUT ROWID, STRICT tables) that don't have direct MySQL equivalents.
Going the other direction — MySQL to SQLite — is rarer but also doable, usually for offline analysis, embedded copies of a subset of data, or test fixtures.
The point: choosing SQLite today doesn't lock you in. The SQL you write transfers, and so does your understanding.
Next: SQLite vs PostgreSQL
MySQL is the most common comparison, but PostgreSQL is the other database you'll see SQLite stacked against — and the differences there are different again. That's the next page.
Frequently Asked Questions
What is the main difference between SQLite and MySQL?
SQLite is an embedded database — a single file your app reads and writes directly, with no server process. MySQL is a client-server database: a separate mysqld process listens on a port, and your app talks to it over the network. That one architectural difference drives almost every other tradeoff between them.
Is SQLite faster than MySQL?
For a single process doing reads and small writes, yes — SQLite skips the network round trip and inter-process overhead, so it's often faster. For many concurrent writers, MySQL wins easily because SQLite serializes writes at the database level. The right answer depends on your workload, not the engines in the abstract.
When should I use SQLite instead of MySQL?
Use SQLite for embedded apps, mobile, desktop tools, CLI utilities, local caches, tests, and small-to-medium websites with one application server. Reach for MySQL when you need multiple application servers hitting one database, fine-grained user permissions, or a write workload heavy enough that row-level locking matters.
Can I migrate from SQLite to MySQL later?
Yes, and it's a common path. The SQL dialects overlap heavily for CREATE TABLE, INSERT, and SELECT, but you'll need to adjust types (INTEGER PRIMARY KEY becomes INT AUTO_INCREMENT), date functions, and any SQLite-specific features like WITHOUT ROWID or partial unique indexes. Tools like pgloader and custom dump scripts handle most of the work.