Skip to content
SQLite

SQLite: database is locked

database is locked (another connection holds a lock on the database file)

Applies to: SQLite 3.x (examples run on 3.39.2; shell output from 3.50.6); WAL mode from 3.7.0
Last technically reviewed 24 October 2026 on SQLite 3.39.2 (PHP PDO_SQLITE) and the sqlite3 shell 3.50.6
The full message
database is locked
Other forms of this message
sqlite3 shell (3.50.6), running a script
Runtime error near line 2: database is locked (5)
sqlite3 shell (3.50.6), SQL given on the command line
Error: stepping, database is locked (5)
PHP PDO (after its busy timeout, 60 seconds by default)
SQLSTATE[HY000]: General error: 5 database is locked
Python sqlite3 (raised as sqlite3.OperationalError)
sqlite3.OperationalError: database is locked
A different error: a conflict inside the same connection (SQLITE_LOCKED, 6)
database table is locked
Result code
SQLITE_BUSY (5); extended SQLITE_BUSY_SNAPSHOT (517) in WAL mode; SQLITE_BUSY_RECOVERY (261) during WAL recovery
Product
SQLite library
Versions
SQLite 3.x (examples run on 3.39.2; shell output from 3.50.6); WAL mode from 3.7.0
Last reviewed
24 October 2026

What it means

This error means another connection was writing to (or, in rollback-journal mode, reading from) the database file, and your statement gave up waiting for the lock.

SQLite allows many readers but only one writer per database file at a time. A connection that starts writing takes a lock on the file; any other connection that also wants to write gets SQLITE_BUSY. In the default rollback-journal mode the conflict also runs the other way: a writer cannot commit while another connection holds an open read transaction, and nobody can read while a writer holds the EXCLUSIVE lock to update the file. The lock belongs to a connection, so a common cause is in the same program: a second connection, an unfinished transaction or an unread result set that keeps a read transaction open. A database browser left open on the same file with uncommitted changes has the same effect.

Whether you see the error at once depends on the busy timeout. With a timeout, SQLite retries until the lock clears or the time is up; with 0 it fails immediately. The C library, the PHP SQLite3 class and the sqlite3 shell start at 0; PHP PDO sets 60 seconds (we read 60000 ms from PRAGMA busy_timeout) and Python's sqlite3 module defaults to 5 seconds, so in those the error means the wait expired. In some cases SQLite returns SQLITE_BUSY without waiting, because waiting could never succeed: when a connection with an open read transaction tries to write while another connection is already committing, and in WAL mode when another connection has written since your transaction read its snapshot (extended code 517, SQLITE_BUSY_SNAPSHOT). A related message, "database table is locked" (SQLITE_LOCKED), is a conflict inside one connection: we reproduced it with the PHP SQLite3 class by running DROP TABLE while a SELECT on the same connection was still being read.

Common causes

  • Two connections write at the same time: two processes, two threads with their own connections, or a web server handling requests in parallel.
  • A transaction or result set is left open: no COMMIT after BEGIN, a cursor or statement that was not fully read or closed, or an exception path that skips the rollback.
  • In rollback-journal mode, a long read in one connection blocks another connection's commit.
  • A transaction that starts by reading (plain BEGIN, the default DEFERRED) later tries to write while another connection is already writing, so the upgrade fails at once.
  • The database is on a network file system, where file locking is unreliable, or a tool such as a database browser keeps the file locked.

Diagnose it

Read-only These statements only read the schema (sqlite_schema and read-only PRAGMA queries) or your own data. They do not change data, settings or the database file, so they are safe to run first.

Which journal mode is the database using?

PRAGMA journal_mode;
What to look for

delete (the default), truncate or persist are rollback-journal modes, where readers and a committing writer block each other. wal means readers and the writer run side by side and only writers conflict.

How long does this connection wait for a lock?

PRAGMA busy_timeout;
What to look for

The timeout in milliseconds for the connection that runs it. 0 means a lock is reported at once. PHP PDO connections show 60000 unless ATTR_TIMEOUT is set.

Are both programs opening the same file?

PRAGMA database_list;
What to look for

The full path of each attached database. Compare it across the programs involved, and check whether the path is on a network share, where SQLite locking cannot be relied on.

Look for the other connection

Find what else has the file open: another instance of your application, a background job, a database browser or an open sqlite3 shell with an uncommitted BEGIN. On Linux, lsof /path/to/shop.db or fuser /path/to/shop.db lists the processes; on Windows, Resource Monitor (CPU tab, Associated Handles) searches by file name. In your code, check that every BEGIN has a COMMIT or ROLLBACK on every path and that result sets are read to the end or closed.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Set a busy timeout so short locks are waited out

Changes configuration

Most locks last milliseconds. A timeout of a few seconds lets SQLite retry instead of failing. It is per connection, so set it every time you connect. In drivers: PDO PDO::ATTR_TIMEOUT (seconds), the PHP SQLite3 class busyTimeout() (milliseconds), Python sqlite3.connect(path, timeout=...) (seconds).

PRAGMA busy_timeout = 5000;  -- wait up to 5 seconds

Keep transactions short and always end them

Client or network side

Do slow work (network calls, file processing, user input) outside the transaction, commit as soon as the writes are done, and roll back in every error path (a try/finally block or the driver's context manager). Read result sets to the end or close them, because an open statement keeps its read transaction alive.

Start read-then-write transactions with BEGIN IMMEDIATE

Changes data

A plain BEGIN takes no lock until the first statement, and a transaction that reads first and writes later can fail at the write without waiting. BEGIN IMMEDIATE takes the write lock at the start, where the busy timeout applies; once it succeeds, no other connection can start writing until you commit, and in WAL mode your reads cannot go stale.

BEGIN IMMEDIATE;
SELECT total FROM orders WHERE id = 1;
UPDATE orders SET total = total + 5 WHERE id = 1;
COMMIT;

Switch to WAL mode so readers and the writer do not block each other

Changes configuration

In WAL mode, readers keep reading while a writer works, and a writer can commit while readers are active. There is still only one writer at a time, so keep the busy timeout. The setting is stored in the database file and stays in effect for every connection. WAL needs every connection on the same machine (it does not work over a network file system) and creates -wal and -shm files next to the database, so the folder must be writable.

PRAGMA journal_mode = WAL;

Retry the whole transaction after SQLITE_BUSY_SNAPSHOT

Client or network side

In WAL mode, if another connection committed after your transaction read its data, your write fails at once (extended code 517) and waiting will not help, because your snapshot is out of date. Roll back, then run the transaction again from the beginning. BEGIN IMMEDIATE avoids this case for transactions that will write.

Examples

A second writer while another connection holds a write transaction

Session B received the error on its INSERT; its SELECT ran. With a busy timeout, B would wait until A commits or the timeout expires.

CREATE TABLE orders (id INTEGER PRIMARY KEY, total REAL);

-- Session A
BEGIN IMMEDIATE;
INSERT INTO orders (total) VALUES (20);

-- Session B: reading still works, writing does not
SELECT COUNT(*) FROM orders;
INSERT INTO orders (total) VALUES (30);

-- Session A
COMMIT;
Result
database is locked

Reproduced on SQLite 3.39.2, 24 October 2026.

A reader blocked by an exclusive writer (rollback-journal mode)

Session B received the error on its SELECT. A writer also takes this exclusive lock while it commits, so a reader can briefly hit it in normal use. In WAL mode the same SELECT runs (we checked).

CREATE TABLE orders (id INTEGER PRIMARY KEY, total REAL);
INSERT INTO orders (total) VALUES (10);

-- Session A
BEGIN EXCLUSIVE;

-- Session B
SELECT COUNT(*) FROM orders;

-- Session A
COMMIT;
Result
database is locked

Reproduced on SQLite 3.39.2, 24 October 2026.

An open read transaction blocks another connection's write

Session A received the error: in rollback-journal mode it cannot write the file while B holds a read lock. After B committed, the same INSERT succeeded. In WAL mode A's INSERT succeeds while B is reading.

CREATE TABLE orders (id INTEGER PRIMARY KEY, total REAL);
INSERT INTO orders (total) VALUES (10);

-- Session B: a read inside a transaction that is never committed
BEGIN;
SELECT COUNT(*) FROM orders;

-- Session A
INSERT INTO orders (total) VALUES (40);

-- Session B
COMMIT;
Result
database is locked

Reproduced on SQLite 3.39.2, 24 October 2026.

WAL mode: a stale read transaction cannot write

Session B received the error at once, with extended code 517 (SQLITE_BUSY_SNAPSHOT) when read through the PHP SQLite3 class; PDO reports only 5. A busy timeout does not help here: roll back and retry the transaction.

PRAGMA journal_mode = WAL;
CREATE TABLE orders (id INTEGER PRIMARY KEY, total REAL);
INSERT INTO orders (total) VALUES (10);

-- Session B
BEGIN;
SELECT COUNT(*) FROM orders;

-- Session A: not blocked by B's read in WAL mode
INSERT INTO orders (total) VALUES (80);

-- Session B: its snapshot is now out of date
INSERT INTO orders (total) VALUES (90);
ROLLBACK;
Result
database is locked

Reproduced on SQLite 3.39.2, 24 October 2026.

How to prevent it

Open a connection with a busy timeout of a few seconds, keep write transactions short, start them with BEGIN IMMEDIATE when they will write, and end every transaction on every code path. Use WAL mode for applications where reads and writes overlap, such as web applications and desktop apps with background sync.

Keep the database on a local disk, not a network share. If many processes write heavily at the same time, send the writes through one connection or a queue rather than letting them compete. Never delete the -journal or -wal file to "unlock" a database: they hold changes that are not in the main file yet, and removing them can lose committed data or corrupt the database.

Common questions

How do I fix "database is locked" in SQLite?

Find the other connection that holds the lock (another process, an unfinished transaction or an open result set in your own code) and make it commit sooner. Then set a busy timeout on every connection, start write transactions with BEGIN IMMEDIATE, and consider WAL mode so readers and the writer stop blocking each other.

Does WAL mode remove the error completely?

No. WAL removes conflicts between readers and the writer, but only one connection can write at a time, so a second writer still waits and then gets SQLITE_BUSY. A read transaction that tries to write after another connection committed also fails (SQLITE_BUSY_SNAPSHOT), and must be retried.

I set a busy timeout, so why do I still get the error immediately?

SQLite skips the wait when waiting cannot succeed: a transaction that started by reading tries to write while another connection is already writing or has committed since. Roll back and retry, or start such transactions with BEGIN IMMEDIATE so the wait happens at the start.

What is the difference between "database is locked" and "database table is locked"?

"database is locked" (SQLITE_BUSY, 5) is a conflict with another connection. "database table is locked" (SQLITE_LOCKED, 6) is a conflict inside the same connection, for example dropping a table while a SELECT on it is still being read; finish or close that statement first.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on SQLite 3.39.2 (PHP PDO_SQLITE) and the sqlite3 shell 3.50.6. Messages are the text the SQLite library itself returns (sqlite3_errmsg) for the versions shown.

Still stuck on a SQLite error?

Browse the full SQLite error library, or get hands-on help from an experienced SQL professional.