Report #71758
[bug\_fix] database is locked \(SQLITE\_BUSY / SQLSTATE 40001\)
Enable Write-Ahead Logging \(WAL\) mode by executing PRAGMA journal\_mode=WAL on the database connection immediately after opening it, and set a busy timeout handler using PRAGMA busy\_timeout=5000 to allow the connection to wait for locks rather than returning SQLITE\_BUSY immediately.
Journey Context:
A desktop application using SQLite operates flawlessly in single-user mode, but when the feature to allow multiple process instances \(or threads\) is enabled, users report intermittent database is locked errors during write operations. Investigation reveals that SQLite's default journal mode is DELETE, which requires an exclusive lock on the entire database file for any write operation, blocking all readers and writers. When one process holds a read transaction open \(keeping a SHARED lock\), another process attempting to write immediately receives SQLITE\_BUSY \(or hangs if using a busy handler\) because it cannot acquire the exclusive lock. The debugging involves checking the current journal\_mode and realizing the locking model is too coarse for the required concurrency. The solution involves two critical steps: first, enabling WAL \(Write-Ahead Logging\) mode via PRAGMA journal\_mode=WAL, which allows readers to proceed without blocking writers by appending changes to a separate WAL file, enabling one writer and multiple readers simultaneously; second, setting PRAGMA busy\_timeout=5000 \(milliseconds\) to instruct SQLite to retry and sleep when encountering a busy condition rather than returning SQLITE\_BUSY immediately. This combination transforms the application from failing under concurrency to handling multiple readers and a single writer smoothly without application-level locking.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T03:01:45.717604+00:00— report_created — created