एरर समाधान · डेवलपर एरर

SQLite "database is locked" (SQLITE_BUSY) - Causes and Fixes

Fix SQLite database is locked errors. Enable WAL mode, set busy_timeout, use BEGIN IMMEDIATE, shorten transactions, and avoid network filesystems.

Error messagesqlite3.OperationalError: database is locked

लेखक: SiteDownCheck संपादकीय टीम · अपडेट: अक्टूबर 14, 2026 · 5 मिनट पढ़ने में

SQLite allows many readers but only one writer at a time. When a connection tries to write, or to read while another holds a conflicting lock, and cannot get the lock in time, it returns SQLITE_BUSY (result code 5), shown by most libraries as "database is locked". A related code, SQLITE_LOCKED (6), covers conflicts inside a single connection or shared cache and reads "database table is locked".

sqlite3.OperationalError: database is locked
django.db.utils.OperationalError: database is locked
SQLSTATE[HY000]: General error: 5 database is locked
Error: SQLITE_BUSY: database is locked

The database is not corrupted. Something else holds the write lock longer than your client is willing to wait.

Step 1: set a busy timeout

By default, SQLite fails immediately when the lock is unavailable. A busy timeout tells it to retry for a while:

PRAGMA busy_timeout = 5000;   -- milliseconds, per connection

Many drivers set this through a connection option. Python's sqlite3.connect() has a timeout parameter, which defaults to 5.0 seconds:

import sqlite3
conn = sqlite3.connect("app.db", timeout=30)

In Django, set "OPTIONS": {"timeout": 20} in DATABASES. In other languages, look for "busy timeout" or "busy handler" in your driver. The pragma must be set on every new connection, since it is not stored in the file.

Step 2: turn on WAL mode

The default rollback-journal mode blocks readers while a write is in progress. Write-ahead logging lets readers and one writer work simultaneously:

PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;

The journal_mode setting is persistent in the database file, so you run it once. synchronous = NORMAL is a commonly used pairing with WAL, but it trades a little durability on power loss for speed, so read the SQLite documentation before using it for important data.

WAL creates app.db-wal and app.db-shm next to the database. Keep them together with the main file when you copy or back up the database, and take backups with sqlite3 app.db ".backup 'copy.db'" or VACUUM INTO, not a plain file copy of a live database.

WAL does not work over network filesystems (see below). Writers still queue, so it reduces locking but does not remove the single-writer limit.

Step 3: avoid the lock-upgrade trap

This is the most surprising cause. By default, a transaction begins as DEFERRED: it starts with no lock, takes a read lock on the first read, and tries to upgrade to a write lock on the first write. If another connection wrote in between, SQLite cannot upgrade, and it returns SQLITE_BUSY immediately, without waiting for the busy timeout, because waiting could deadlock.

If a transaction will write, start it as a write transaction:

BEGIN IMMEDIATE;
SELECT balance FROM accounts WHERE id = 1;
UPDATE accounts SET balance = balance - 10 WHERE id = 1;
COMMIT;

BEGIN IMMEDIATE takes the write lock up front, so the busy timeout applies, and conflicts are handled by waiting rather than by a failed upgrade. In Python, set isolation_level appropriately or issue BEGIN IMMEDIATE yourself. Some frameworks expose a transaction mode setting.

Step 4: find who holds the lock

Typical lock holders:

  • A long transaction. Code that opens a transaction, then makes an HTTP call or waits on user input before committing. Keep transactions short and do slow work outside them.
  • An unfinished read. A cursor left open, or a statement not reset or finalized, keeps a read lock. Fetch all rows or close the cursor.
  • Another process. A cron script, backup job, or a database browser GUI with an open write transaction. On Linux:
fuser -v app.db
lsof app.db
  • A crashed process. Locks are released when the process exits. A stale -journal file next to the database is a hot journal, and SQLite rolls it back automatically on the next open, provided it has write permission to the directory.
  • Too many app workers writing concurrently. Eight web workers each writing per request is heavy for one SQLite file. Serialize writes through one queue, or move to a client-server database when write concurrency grows.

Step 5: filesystem and permissions

  • Network filesystems (NFS, SMB, some shared volumes). File locking there is unreliable, and SQLite documents that it can fail or corrupt data. Keep the database on a local disk. In Docker, avoid bind mounts from network shares or some Windows and Mac host mounts for write-heavy databases, and use a named volume.
  • Directory not writable. SQLite needs write access to the directory to create the journal or WAL files, not only to the file itself. Check the owner and mode of both.
  • Read-only mounts give a different error, attempt to write a readonly database, but are often confused with locking.

Verify

PRAGMA journal_mode;
PRAGMA busy_timeout;
PRAGMA integrity_check;

Expect wal, your timeout value, and ok. Then run a concurrency test with several writers in parallel and confirm no failures. Check a database-backed page with the वेबसाइट हेल्थ चेक. An अपटाइम मॉनिटर with a keyword assertion catches an application that starts returning database errors, and nightly jobs that touch the file can be tracked with cron monitoring.

अगले कदम

सामान्य प्रश्न

Does SQLite support multiple writers?

No. Only one connection can write at a time. WAL lets readers continue during a write, and the busy timeout makes writers wait their turn.

What is the difference between SQLITE_BUSY and SQLITE_LOCKED?

BUSY means another connection, often in another process, holds a conflicting lock. LOCKED means a conflict within the same connection or shared cache.

Is it safe to delete the -wal or -shm files?

Not while the database may be in use or if the WAL has unmerged data, because you can lose committed transactions. Let SQLite checkpoint and clean them up.

Should I just switch to PostgreSQL?

Not necessarily. SQLite handles many small sites well with WAL and short transactions. Consider a server database when you need heavy concurrent writes or multiple application servers.

Get notified when this fix updates

Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.

यह पेज सामान्य जानकारी है, जिसे हमारी संपादकीय टीम ने लिखा है और दस्तावेज़ीकरण बदलने पर अपडेट किया जाता है। सर्वर और प्रदाता अलग-अलग होते हैं, इसलिए बदलाव पहले सुरक्षित तरीके से जाँचें। देखें: संपादकीय नीति और अस्वीकरण.