Database Troubleshooting¶
This guide covers SQLite database structure, common issues, recovery procedures, and optimization techniques for qBitrr's persistent storage.
Overview¶
qBitrr uses a single consolidated SQLite database to maintain persistent state across restarts:
| Database File | Purpose | Location |
|---|---|---|
qbitrr.db | Single consolidated database for all Arr instances and WebUI data | ~/config/qBitManager/ or /config/qBitManager/ |
qbitrr.db-wal | Write-Ahead Log (uncommitted changes) | Same directory |
qbitrr.db-shm | Shared memory index for WAL mode | Same directory |
Database Consolidation (v5.8.0+)
As of version 5.8.0, qBitrr uses a single qbitrr.db file instead of separate per-instance databases. All data is isolated using the ArrInstance field in each table.
Database Modes
qBitrr uses SQLite's WAL (Write-Ahead Logging) mode for better concurrency and crash resilience. WAL mode creates -wal and -shm temporary files alongside the main database.
Migration from v5.7.x¶
When upgrading from v5.7.x or earlier:
- Old databases are automatically deleted on first startup (Radarr-.db, Sonarr-.db, Lidarr.db, webui_activity.db)
- New consolidated database is created (
qbitrr.db) - Data is automatically re-synced from your Arr instances (takes 5-30 minutes depending on library size)
- No manual intervention required - this happens automatically
Database Schema¶
Consolidated Database Tables¶
ArrInstance Field
All tables include an ArrInstance field (added in v5.8.0) to isolate data by Arr instance within the single consolidated database:
TorrentLibrary¶
Tracks all managed torrents across qBittorrent.
CREATE TABLE torrentlibrary (
ArrInstance TEXT DEFAULT "", -- Arr instance name
Hash TEXT NOT NULL, -- qBittorrent torrent hash
Category TEXT NOT NULL, -- qBittorrent category
AllowedSeeding BOOLEAN, -- Can seed (passed health checks)
Imported BOOLEAN, -- Successfully imported to Arr
AllowedStalled BOOLEAN, -- Exempt from stalled checks
FreeSpacePaused BOOLEAN -- Paused by free space manager
);
Fields:
- Hash: Unique torrent identifier from qBittorrent
- Category: Maps to Radarr/Sonarr/Lidarr category in config
- AllowedSeeding:
Trueif torrent passed health checks and can seed - Imported:
Trueif files successfully imported to Arr instance - AllowedStalled:
Trueif torrent is exempt from stalled detection - FreeSpacePaused:
Trueif paused by disk space manager
MoviesFilesModel (Radarr)¶
Tracks movie library state and search history.
CREATE TABLE moviesfilesmodel (
ArrInstance TEXT DEFAULT "", -- Arr instance name (e.g., "Radarr-4K")
Title TEXT,
Monitored BOOLEAN,
TmdbId INTEGER,
Year INTEGER,
EntryId INTEGER UNIQUE, -- Radarr movie ID
Searched BOOLEAN, -- Searched for this movie
MovieFileId INTEGER, -- Current file ID (0 = missing)
IsRequest BOOLEAN, -- From Overseerr/Ombi
QualityMet BOOLEAN, -- Quality cutoff met
Upgrade BOOLEAN, -- Upgrade in progress
CustomFormatScore INTEGER, -- Current CF score
MinCustomFormatScore INTEGER, -- Target CF score
CustomFormatMet BOOLEAN, -- CF score met
Reason TEXT, -- Why searched/upgraded
QualityProfileId INTEGER, -- Current profile ID
QualityProfileName TEXT, -- Current profile name
LastProfileSwitchTime DATETIME, -- Last profile change
CurrentProfileId INTEGER, -- Active profile ID
OriginalProfileId INTEGER -- Original profile ID
);
Key Fields:
- EntryId: Primary key, matches Radarr's movie ID
- Searched: Tracks if automated search was triggered
- QualityMet:
Truewhen quality cutoff reached - CustomFormatScore: Current score vs. MinCustomFormatScore
- Profile Tracking: Supports profile switching for searches
SeriesFilesModel (Sonarr)¶
Tracks TV series library state.
CREATE TABLE seriesfilesmodel (
EntryId INTEGER PRIMARY KEY, -- Sonarr series ID
Title TEXT,
Monitored BOOLEAN,
Searched BOOLEAN,
Upgrade BOOLEAN,
MinCustomFormatScore INTEGER,
QualityProfileId INTEGER,
QualityProfileName TEXT
);
EpisodeFilesModel (Sonarr)¶
Tracks individual episodes (granular tracking).
CREATE TABLE episodefilesmodel (
EntryId INTEGER PRIMARY KEY, -- Sonarr episode ID
SeriesTitle TEXT,
Title TEXT,
SeriesId INTEGER NOT NULL,
EpisodeFileId INTEGER,
EpisodeNumber INTEGER NOT NULL,
SeasonNumber INTEGER NOT NULL,
AbsoluteEpisodeNumber INTEGER,
SceneAbsoluteEpisodeNumber INTEGER,
AirDateUtc DATETIME,
Monitored BOOLEAN,
Searched BOOLEAN,
IsRequest BOOLEAN,
QualityMet BOOLEAN,
Upgrade BOOLEAN,
CustomFormatScore INTEGER,
MinCustomFormatScore INTEGER,
CustomFormatMet BOOLEAN,
Reason TEXT,
QualityProfileId INTEGER,
QualityProfileName TEXT,
LastProfileSwitchTime DATETIME,
CurrentProfileId INTEGER,
OriginalProfileId INTEGER
);
AlbumFilesModel (Lidarr)¶
Tracks music albums.
CREATE TABLE albumfilesmodel (
Title TEXT,
Monitored BOOLEAN,
ForeignAlbumId TEXT, -- MusicBrainz ID
ReleaseDate DATETIME,
EntryId INTEGER UNIQUE, -- Lidarr album ID
Searched BOOLEAN,
AlbumFileId INTEGER,
IsRequest BOOLEAN,
QualityMet BOOLEAN,
Upgrade BOOLEAN,
CustomFormatScore INTEGER,
MinCustomFormatScore INTEGER,
CustomFormatMet BOOLEAN,
Reason TEXT,
ArtistId INTEGER NOT NULL,
ArtistTitle TEXT,
QualityProfileId INTEGER,
QualityProfileName TEXT,
LastProfileSwitchTime DATETIME,
CurrentProfileId INTEGER,
OriginalProfileId INTEGER
);
TrackFilesModel (Lidarr)¶
Tracks individual music tracks.
CREATE TABLE trackfilesmodel (
EntryId INTEGER PRIMARY KEY, -- Lidarr track ID
AlbumId INTEGER NOT NULL,
TrackNumber INTEGER,
Title TEXT,
Duration INTEGER, -- Duration in seconds
HasFile BOOLEAN,
TrackFileId INTEGER,
Monitored BOOLEAN
);
ArtistFilesModel (Lidarr)¶
Tracks music artists.
CREATE TABLE artistfilesmodel (
EntryId INTEGER PRIMARY KEY, -- Lidarr artist ID
Title TEXT,
Monitored BOOLEAN,
Searched BOOLEAN,
Upgrade BOOLEAN,
MinCustomFormatScore INTEGER,
QualityProfileId INTEGER,
QualityProfileName TEXT
);
Queue Models¶
Track import queue state.
CREATE TABLE moviequeuemodel (
EntryId INTEGER UNIQUE,
Completed BOOLEAN DEFAULT FALSE
);
CREATE TABLE episodequeuemodel (
EntryId INTEGER UNIQUE,
Completed BOOLEAN DEFAULT FALSE
);
CREATE TABLE albumqueuemodel (
EntryId INTEGER UNIQUE,
Completed BOOLEAN DEFAULT FALSE
);
SearchActivity (WebUI)¶
Tracks search activity for the WebUI dashboard.
CREATE TABLE searchactivity (
category TEXT PRIMARY KEY, -- Arr instance category
summary TEXT, -- Search summary/status
timestamp TEXT -- Last search timestamp
);
Consolidated in v5.8.0
Prior to v5.8.0, each Arr instance had separate database files. Now all data is in the single qbitrr.db file with the ArrInstance field providing isolation.
Common Database Issues¶
1. Database Locked Errors¶
Symptoms:
Causes:
- Multiple qBitrr instances accessing the same database
- Long-running transactions blocking writes
- File system latency (NFS, cloud storage)
Solutions:
# Docker
docker ps --filter name=qbitrr
# Systemd
systemctl status qbitrr
# Manual check
ps aux | grep qbitrr
Stop duplicate instances before proceeding.
qBitrr automatically retries locked operations with exponential backoff:
Internal retry logic (automatic):
- Attempt 1: Wait 0.5s
- Attempt 2: Wait 1.0s
- Attempt 3: Wait 2.0s
- Attempt 4: Wait 4.0s
- Attempt 5: Wait 8.0s (max 10s)
If locks persist beyond 5 retries:
2. Database Corruption¶
Symptoms:
Causes:
- Unexpected shutdown (power loss, container crash)
- Disk full during write operation
- Hardware failures (bad sectors, memory errors)
- File system corruption (ext4, btrfs, zfs)
Automatic Recovery:
qBitrr automatically attempts recovery when corruption is detected:
- WAL Checkpoint: Flushes WAL to main database
- Full Repair: Dumps recoverable data to new database
- Backup: Original database saved as
qbitrr.db.backup
Manual Recovery:
# Stop qBitrr
docker stop qbitrr
# Backup corrupted database
cp ~/config/qbitrr.db ~/config/qbitrr.db.corrupt
# Dump recoverable data
sqlite3 ~/config/qbitrr.db ".dump" > ~/config/dump.sql
# Create new database from dump
rm ~/config/qbitrr.db
sqlite3 ~/config/qbitrr.db < ~/config/dump.sql
# Verify
sqlite3 ~/config/qbitrr.db "PRAGMA integrity_check;"
# Restart
docker start qbitrr
Data Loss
- WAL Checkpoint: No data loss if successful
- Dump/Restore: May lose corrupted rows/tables
- Fresh Start: Loses all history (searches, import state, torrent tracking)
3. Disk I/O Errors¶
Symptoms:
Causes:
- Disk full (no space for WAL or temp files)
- Failing storage device (HDD, SSD wear)
- Network storage issues (NFS, SMB timeouts)
- File system errors (unmounted, read-only)
Diagnosis:
qBitrr requires: - Minimum 100MB free for WAL operations - ~2x database size for VACUUM operations
Ensure qBitrr user owns the database:
Solutions:
- Free Disk Space: Delete old logs, torrents, or unused files
- Fix Permissions: Ensure qBitrr can read/write database
- Move Database: Relocate to healthier storage
4. Duplicate Entry Errors¶
Symptoms:
Causes:
- Race condition during multi-threaded writes (rare)
- Manual database modifications
- Database restored from backup while qBitrr was running
Solutions:
# Stop qBitrr
docker stop qbitrr
# Identify duplicate
sqlite3 ~/config/qbitrr.db << EOF
SELECT EntryId, COUNT(*) as count
FROM moviesfilesmodel
GROUP BY EntryId
HAVING count > 1;
EOF
# Delete duplicate (keep first entry)
sqlite3 ~/config/qbitrr.db << EOF
DELETE FROM moviesfilesmodel
WHERE rowid NOT IN (
SELECT MIN(rowid)
FROM moviesfilesmodel
GROUP BY EntryId
);
EOF
# Restart
docker start qbitrr
5. Missing Tables¶
Symptoms:
Causes:
- Database created by older qBitrr version
- Incomplete migration from previous version
- Corrupted schema
Solutions:
Expected tables: - torrentlibrary - moviesfilesmodel, moviequeuemodel - seriesfilesmodel, episodefilesmodel, episodequeuemodel - albumfilesmodel, trackfilesmodel, artistfilesmodel, albumqueuemodel
Manual Database Operations¶
Stop qBitrr First
Always stop qBitrr before direct database manipulation to avoid corruption.
Inspecting Database¶
# Open interactive shell
sqlite3 ~/config/qbitrr.db
# List all tables
.tables
# Show table schema
.schema moviesfilesmodel
# Query movies
SELECT Title, Monitored, QualityMet, CustomFormatMet
FROM moviesfilesmodel
WHERE Monitored = 1 AND QualityMet = 0
LIMIT 10;
# Count torrents by category
SELECT Category, COUNT(*) as count
FROM torrentlibrary
GROUP BY Category;
# Show movies searched recently
SELECT Title, Searched, Reason
FROM moviesfilesmodel
WHERE Searched = 1
ORDER BY EntryId DESC
LIMIT 20;
Resetting Search State¶
# Reset all movie searches (triggers new automated search)
sqlite3 ~/config/qbitrr.db << EOF
UPDATE moviesfilesmodel SET Searched = 0 WHERE Searched = 1;
EOF
# Reset specific movie
sqlite3 ~/config/qbitrr.db << EOF
UPDATE moviesfilesmodel SET Searched = 0 WHERE EntryId = 123;
EOF
# Reset TV series searches
sqlite3 ~/config/qbitrr.db << EOF
UPDATE seriesfilesmodel SET Searched = 0 WHERE Searched = 1;
EOF
# Reset episode searches
sqlite3 ~/config/qbitrr.db << EOF
UPDATE episodefilesmodel SET Searched = 0 WHERE Searched = 1;
EOF
Clearing Torrent Tracking¶
# Remove specific torrent
sqlite3 ~/config/qbitrr.db << EOF
DELETE FROM torrentlibrary WHERE Hash = 'abc123...';
EOF
# Clear all torrents for category
sqlite3 ~/config/qbitrr.db << EOF
DELETE FROM torrentlibrary WHERE Category = 'radarr-movies';
EOF
# Clear all torrents (CAUTION: qBitrr re-adds active torrents)
sqlite3 ~/config/qbitrr.db << EOF
DELETE FROM torrentlibrary;
EOF
Forcing Profile Switch¶
# Reset profile tracking (allows new switch attempt)
sqlite3 ~/config/qbitrr.db << EOF
UPDATE moviesfilesmodel
SET LastProfileSwitchTime = NULL,
CurrentProfileId = OriginalProfileId
WHERE EntryId = 123;
EOF
Database Backup & Restore¶
Automated Backups¶
qBitrr automatically creates backups during recovery:
- Location:
~/config/qbitrr.db.backup - Trigger: Before repair operations
- Retention: Single backup (overwrites previous)
Manual Backups¶
# Stop qBitrr
docker stop qbitrr
# Backup consolidated database (v5.8.0+)
cp ~/config/qBitManager/qbitrr.db ~/backups/qbitrr-$(date +%Y%m%d).db
# Also backup WAL and SHM files for consistency
cp ~/config/qBitManager/qbitrr.db* ~/backups/
# Restart
docker start qbitrr
Single File Backup
With the consolidated database, you only need to backup one file (qbitrr.db) instead of multiple per-instance databases!
Restore from Backup¶
# Stop qBitrr
docker stop qbitrr
# Restore database
cp ~/backups/qbitrr-20231127.db ~/config/qbitrr.db
# Verify integrity
sqlite3 ~/config/qbitrr.db "PRAGMA integrity_check;"
# Restart
docker start qbitrr
Performance Optimization¶
VACUUM Database¶
Reclaims space and optimizes database file.
# Stop qBitrr
docker stop qbitrr
# Run VACUUM
sqlite3 ~/config/qbitrr.db "VACUUM;"
# Check new size
ls -lh ~/config/qbitrr.db
# Restart
docker start qbitrr
When to VACUUM:
- After deleting large amounts of data
- Database file much larger than expected
- Query performance degradation
Requirements:
- Free disk space: ~2x current database size
- Downtime: 5-60 seconds depending on database size
ANALYZE Statistics¶
Updates query planner statistics for better performance.
Run after:
- Adding/deleting many rows
- Query performance issues
- Database grows significantly
PRAGMA Settings¶
qBitrr uses optimized PRAGMA settings (automatically applied):
PRAGMA journal_mode=WAL; -- Write-Ahead Logging
PRAGMA synchronous=NORMAL; -- Balance safety vs. speed
PRAGMA cache_size=-64000; -- 64MB cache
PRAGMA temp_store=MEMORY; -- Temp tables in RAM
PRAGMA mmap_size=268435456; -- 256MB memory-mapped I/O
Tuning
These settings are tuned for typical workloads. Adjust only if experiencing issues:
Database Monitoring¶
Health Checks¶
qBitrr performs automatic health checks every 10 event loop iterations:
# Internal code (automatic)
healthy, msg = check_database_health(db_path)
if not healthy:
logger.warning("Database unhealthy: %s", msg)
# Automatic recovery attempted
Manual Health Check:
# Quick check (fast)
sqlite3 ~/config/qbitrr.db "PRAGMA quick_check;"
# Full integrity check (slow, thorough)
sqlite3 ~/config/qbitrr.db "PRAGMA integrity_check;"
Expected output: ok
Database Size Monitoring¶
# Check database size
ls -lh ~/config/*.db
# Check WAL size (should be small)
ls -lh ~/config/*.db-wal
Typical Sizes:
| Library Size | Database Size | WAL Size |
|---|---|---|
| Small (< 500 items) | 1-5 MB | < 1 MB |
| Medium (500-5,000) | 5-50 MB | 1-5 MB |
| Large (5,000-50,000) | 50-500 MB | 5-20 MB |
| Very Large (> 50,000) | 500 MB - 2 GB | 20-100 MB |
Large WAL Files
If WAL file grows beyond 100 MB:
Query Performance Analysis¶
# Enable query timer
sqlite3 ~/config/qbitrr.db << EOF
.timer ON
.eqp ON
-- Test slow query
SELECT * FROM moviesfilesmodel WHERE Monitored = 1 AND QualityMet = 0;
EOF
If queries are slow:
- Run
ANALYZE; - Check database size (may need VACUUM)
- Consider adding indexes (advanced)
Database Migration¶
Upgrading qBitrr¶
qBitrr automatically handles database migrations during startup:
# Internal migration logic (automatic)
CURRENT_CONFIG_VERSION = 15
apply_config_migrations() # Migrates database schema
Manual Verification:
# Check schema version (no built-in version field)
sqlite3 ~/config/qbitrr.db << EOF
.schema
EOF
# Compare with expected schema (see "Database Schema" section)
Downgrading qBitrr¶
Downgrade Risk
Downgrading qBitrr may fail if newer version added database fields.
Safe Downgrade:
# Backup database
cp ~/config/qbitrr.db ~/backups/qbitrr-before-downgrade.db
# Delete database (force rebuild)
rm ~/config/qbitrr.db
# Downgrade qBitrr
docker pull feramance/qbitrr:5.2.0
docker stop qbitrr && docker rm qbitrr
# Start old version (rebuilds database)
docker run -d --name qbitrr feramance/qbitrr:5.2.0 ...
Advanced Topics¶
WAL Mode Details¶
qBitrr uses SQLite's Write-Ahead Logging (WAL) mode for:
- Concurrent Access: Readers don't block writers
- Crash Recovery: Automatic rollback on unexpected shutdown
- Performance: Faster writes (batched commits)
WAL Files:
qbitrr.db-wal: Write-ahead log (uncommitted changes)qbitrr.db-shm: Shared memory index for WAL
Checkpoint Modes:
| Mode | Description | Use Case |
|---|---|---|
| PASSIVE | Checkpoint without blocking | Background maintenance |
| FULL | Checkpoint all frames | Before backup |
| RESTART | Reset WAL to beginning | After large writes |
| TRUNCATE | Checkpoint + shrink WAL | Reclaim disk space |
Multi-Process Coordination¶
qBitrr uses inter-process file locks to coordinate database access:
# Lock file: ~/config/qbitrr.db.lock
with database_lock():
# All database operations here
db.execute_sql("UPDATE ...")
Lock Mechanism:
- Windows:
msvcrt.locking()(mandatory locks) - Linux/macOS:
fcntl.flock()(advisory locks)
Re-entrant: Same process can acquire lock multiple times (reference counting).
Custom Indexes¶
For very large libraries (50,000+ items), consider adding indexes:
-- Speed up monitored + quality queries
CREATE INDEX IF NOT EXISTS idx_movies_quality
ON moviesfilesmodel(Monitored, QualityMet, CustomFormatMet);
-- Speed up episode lookups
CREATE INDEX IF NOT EXISTS idx_episodes_series
ON episodefilesmodel(SeriesId, SeasonNumber, EpisodeNumber);
-- Speed up torrent hash lookups
CREATE INDEX IF NOT EXISTS idx_torrents_hash
ON torrentlibrary(Hash);
Index Overhead
Indexes speed up reads but slow down writes. Only add if experiencing performance issues.
Related Documentation¶
- Debug Logging - Log analysis for database errors
- Common Issues - General troubleshooting
- Docker Guide - Docker-specific database issues
- Path Mapping - File access issues affecting database operations
Quick Reference¶
Common Commands¶
# Check database health
sqlite3 ~/config/qbitrr.db "PRAGMA quick_check;"
# View tables
sqlite3 ~/config/qbitrr.db ".tables"
# Checkpoint WAL
sqlite3 ~/config/qbitrr.db "PRAGMA wal_checkpoint(TRUNCATE);"
# Vacuum database
sqlite3 ~/config/qbitrr.db "VACUUM;"
# Backup database
cp ~/config/qbitrr.db ~/backups/qbitrr-$(date +%Y%m%d).db
# Reset all searches
sqlite3 ~/config/qbitrr.db "UPDATE moviesfilesmodel SET Searched = 0;"
Emergency Recovery¶
# 1. Stop qBitrr
docker stop qbitrr
# 2. Backup corrupted database
cp ~/config/qbitrr.db ~/config/qbitrr.db.corrupt
# 3. Attempt repair
sqlite3 ~/config/qbitrr.db ".dump" | sqlite3 ~/config/qbitrr.db.new
mv ~/config/qbitrr.db.new ~/config/qbitrr.db
# 4. Verify
sqlite3 ~/config/qbitrr.db "PRAGMA integrity_check;"
# 5. Restart
docker start qbitrr
If repair fails, delete database and rebuild:
Related Documentation¶
Troubleshooting¶
- Common Issues - General troubleshooting guide
- Debug Logging - Enable detailed logging for diagnosis
- Docker Troubleshooting - Docker-specific issues
- Path Mapping - File access problems
- Performance Tuning - Optimize qBitrr performance
Configuration¶
- Configuration Guide - All configuration options
- Environment Variables - ENV var configuration
Advanced¶
- API Reference - Direct database access via API
- Development Guide - Database schema details
Need Help?¶
If database issues persist after following this guide:
- Collect Information:
- qBitrr version:
docker exec qbitrr qbitrr --version - Database size:
ls -lh ~/config/*.db* -
Recent errors:
tail -n 100 ~/config/logs/Main.log -
Try Emergency Recovery:
- Stop qBitrr
- Backup database
- Delete database (forces rebuild)
-
Restart qBitrr
-
Get Support:
- GitHub Issues - Report database bugs
- FAQ - Check for known database issues
- Provide: qBitrr version, error messages, database size, storage type (local/NFS/SMB)