Resolving Emby Docker Container SQLite Database Locks
The unexpected database lockup
Recently, a hardware crash left the Emby media server instance I run in my personal environment in a broken state, with the Docker container repeatedly failing to start due to a SQLite database lock.
Emby comes in multiple deployment options. In my setup, it’s containerized and hosted on a XCP-ng VM, a frequent deployment method in the enterprise as well where I still see a mojority of container runtimes hosted in VM, as this provides stronger isolation and portability without having the challenge of managing dependencies - the famous “it ran fine on my machine”.
Back to the issue at hand, the container I ran is itself from the official project. The problem emerged after a hardware-induced hypervisor crash. The automatic reboot sequence restored most services, but my Emby container became trapped in a restart loop and greeting me with a cryptic SQLite error:
Info SqliteItemRepository: Opening sqlite connection to /config/data/library.db
Error Main: Error in appHost.Init
*** Error Report ***
SQLitePCL.pretty.SQLiteException: Busy: database is locked - PRAGMA journal_mode
SQLitePCL.pretty.SQLiteException: Exception of type 'SQLitePCL.pretty.SQLiteException' was thrown.
at SQLitePCL.pretty.SQLiteDatabaseConnection.PrepareStatement(String sql, ReadOnlySpan`1& tail)
at SQLitePCL.pretty.DatabaseConnection.PrepareStatement(IDatabaseConnection This, String sql)
at Emby.Sqlite.BaseSqliteRepository.CreateConnection(Boolean isReadOnly)
at Emby.Server.Implementations.Data.SqliteItemRepository.Initialize(SqliteUserDataRepository userDataRepo, SyncRepository syncRepo)
at Emby.Server.Implementations.ApplicationHost.InitDatabases()
at Emby.Server.Implementations.ApplicationHost.Init()
at EmbyServer.HostedService.StartAsync(CancellationToken cancellationToken)
Source: SQLitePCL.pretty
TargetSite: SQLitePCL.pretty.IStatement PrepareStatement(System.String, System.ReadOnlySpan`1[System.Byte] ByRef)
In particular, note the log output Busy: database is locked
.
While investigating the issue, I discovered similar SQLite database lock problems aren’t unique to Emby. Jellyfin users β the open-source fork of Emby β have reported comparable challenges. This isn’t surprising, given both projects share their technical lineage and rely on SQLite for metadata and library management.
This error signaled a classic database integrity issue: an incomplete transaction or improperly closed database connection resulting from the ungraceful system shutdown.
The logs revealed the specific database causing trouble: /config/data/library.db
, which handles Emby’s core library metadata and tracking information.
Backup restoration: only as a last resort
Database restorations can be risky.
In enterprise environments, I’ve witnessed countless scenarios where naive backup strategies led to data corruption or complete loss.
VM snapshots backups for instance, are fundamentally blind to the internal state of running applications. They capture a moment in time, but not necessarily a consistent one. Databases maintain complex transaction logs and in-memory states that traditional backup methods can’t fully capture.
Consider a database mid-transaction: a VM backup or VM snapshot might freeze partially completed writes, leading to structural inconsistencies that only manifest later upon restore. This is in my day-job at Forward Systems, we deploy application-aware backup solutions like Bacula to backup all customer critical databases.
Bacula - when implemented properly - will on the other hand understands application-specific transaction states, and therefore ensure data consistency upon restore.
But instead of resorting to restoring from backup , I was thankfully able to resolve the database lock using an ephemeral SQLite container. Hopefully, someone else finds this writeup helful.
The Clean, Containerized Fix
Why Ephemeral Containers Matter
In sensitive enterprise environments, bringing up an interactive shell in a running container is a security risk and I usually recommend such organizations to have policies that immediately terminate containers experiencing state drift or interactive access.
Obviously, my Emby deployment π isn’t a high-security enterprise system , but it’s always good to maintain robust practices. π‘οΈ
The ephemeral container approach offers a clean, secure method to perform maintenance. It’s a disposable, purpose-built solution that leaves no trace after execution.
For containerized deployments β especially on stateless systems like RHCOS, Fedora CoreOS or SUSE MicroOS β the ephemeral container method is not just recommended; it’s often the only viable approach.
Prerequisites
- Docker
- Docker Compose
- An Emby container configuration
Step-by-Step Resolution
- Stop the Emby container:
docker compose down
- Launch an ephemeral SQLite container with your config volume mounted:
docker run --rm -it -v emby_config:/config esolang/sqlite3 /bin/sh
- Clean up and vacuum the database:
cd /config/data
rm library.db-wal library.db-shm
sqlite3 /config/data/library.db "VACUUM;"
exit
- Restart Emby:
docker compose up -d
- Cleanup:
The beauty of the ephemeral container approach lies in its self-cleaning nature. Once you exit the container, it automatically deletes itself β a feature built into Docker’s
--rm
flag. This means no lingering containers, no manual cleanup, just a precise, surgical maintenance operation.
After resolving the database issue, you’ll want to remove any unnecessary images.
docker image prune
Understanding the VACUUM Command
The VACUUM
SQL command is more than just a simple cleanup:
- Rebuilds the entire database file
- Removes deleted data
- Defragments the file
- Recovers unused space
- Resolves potential corruption issues
Hope this helps!