SQLite reports "database is locked" with error code SQLITE_BUSY (5). The file is not damaged. Another connection holds a lock. SQLite allows many readers but only one writer at a time. If you see this error repeatedly, do not delete files. Manage the locks. This guide walks through the causes and the safe fixes, so you keep your data intact.

What "Database is Locked" Really Means

SQLITE_BUSY (5) is a locking error, not corruption. SQLite uses locks to protect the integrity of the database file. A lock prevents two connections from writing at the same time. When one connection holds a write lock, other connections that try to write get the "database is locked" error. The database file itself is still intact.

Confusing a locking error with corruption leads people to try destructive fixes. Do not be one of them.

Common Causes of Persistent Locking Errors

  • Long-running open transactions: A connection that starts a transaction and does not commit or rollback keeps the lock active.
  • Unclosed connections: Applications that open a connection and forget to close it leave locks in place.
  • Network file systems: SQLite's documentation warns that network file systems often have unreliable locking, which can cause persistent locks and even corruption.
  • Concurrent writes: Since SQLite allows only one writer at a time, multiple processes or threads writing at once will trigger lock errors.

Safe Fix 1 Use a Busy Timeout

The simplest way to handle lock conflicts is to tell SQLite to wait. Use a PRAGMA statement to set a busy timeout:

PRAGMA busy_timeout = 5000;

This makes a connection wait up to 5,000 ms for the lock to become available instead of failing immediately. If the lock is released within that time, the operation proceeds. Adjust the timeout value to suit your application. This fix works for many common cases, especially when locks are brief.

Safe Fix 2 Switch to WAL Mode

What WAL Mode Does

WAL mode (Write-Ahead Log) changes how SQLite handles concurrent access. Enable it with:

PRAGMA journal_mode=WAL;

In WAL mode, readers can continue reading while one writer writes. This reduces lock contention significantly. Many applications that need concurrent writes benefit from WAL mode.

When WAL Mode Helps

If your application has frequent concurrent writes and reads, WAL mode is a good choice. It does not eliminate all locking errors, but it makes them much less common. The database remains safe as long as you do not delete the WAL files.

What Not to Do Dangerous Fixes That Cause Corruption

Some online advice suggests deleting files to free a stuck database. These actions can corrupt your data permanently.

  • Deleting the -journal file: The journal file contains uncommitted data that SQLite uses to roll back or recover. Deleting it can lose committed data or leave the database in an inconsistent state.
  • Deleting the -wal file: In WAL mode, the -wal file holds recent changes that have not been written to the main database file yet. Deleting it can corrupt the database.
  • Copying the live file: Copying a SQLite database file while it is being written can produce a copy that is internally inconsistent, leading to corruption when you try to open it.

None of these actions fix a locking error. They only create new problems. Identify why the lock is held and address the root cause.

How to Investigate a Persistent Lock

When a lock does not release, follow these steps:

  1. Check which processes have the database open. On many systems, tools like lsof or fuser can show open file handles.
  2. Look for unclosed connections in your application code. Ensure every connect() has a matching close() or use a context manager.
  3. Verify that all transactions are committed or rolled back. An open transaction holds a lock until it ends.
  4. If the database is on a network file system, move it to local storage. Network file systems often have unreliable locking, as SQLite's documentation warns.

These steps help you find the source of the lock without risking data loss.

Preventing Locking Errors in New Projects

If you are designing a new application that uses SQLite, plan for concurrency from the start. Use WAL mode for any application with concurrent reads and writes. Set a reasonable busy timeout so that brief lock conflicts do not cause errors. Close connections and end transactions promptly. In Python sqlite3, always call .close() on your connection objects. For web applications, use a connection pool that reuses connections safely. These practices reduce the chance of seeing "database is locked" errors.