How to fix SQLITE_READONLY_DIRECTORY: Directory containing database is read-only in SQLite
SQLite cannot write to your database because the directory containing it lacks write permissions. Both the database file and its parent directory must be writable for SQLite to function properly.
Quick fix
Fixes SQLITE_READONLY_DIRECTORY
ls -ld /path/to/database/directory- Check current directory permissions
- Check what user your application runs as
- Fix directory ownership and permissions
- Grant permissions to the database file itself
ls -ld /path/to/database/directorySQLITE_READONLY_DIRECTORY: Directory containing database is read-only
What this error means
SQLite needs to create temporary and journal files (such as -journal, -wal, and -shm files) in the same directory as your database file during normal operations. If the directory containing the database lacks write permissions, SQLite cannot create these essential files and will fail with the SQLITE_READONLY_DIRECTORY error. This happens even if the database file itself is writable—directory permissions take precedence. SQLite uses these temporary files for transaction management, write-ahead logging, and crash recovery. Without write access to the directory, the database becomes effectively read-only to protect data integrity.
Typical symptoms
- Database write operations (INSERT, UPDATE, DELETE) fail unexpectedly
- CREATE TABLE or ALTER TABLE commands are rejected
- Transactions cannot be committed
- Application logs show "SQLITE_READONLY_DIRECTORY" or "attempt to write a readonly database" errors
- Reads work fine, but any modification attempt fails
- Error occurs only in certain environments (production, Docker, shared hosting)
Common causes
- Database directory has restrictive permissions (not writable by the application user)
- Database was created by a different user (e.g., sudo) and application runs as a different user
- Application runs as a web server user (www-data, nginx, apache) without directory write access
- Deployment script did not set proper permissions on the database directory
- Read-only filesystem or directory mounted with read-only flag
- SELinux or AppArmor policies restrict write access to the directory
- Incorrect file ownership preventing the application user from writing
How to fix "SQLITE_READONLY_DIRECTORY: Directory containing database is read-only"
First, verify what permissions the directory currently has and who owns it:
ls -ld /path/to/database/directoryLook for output like:
drwxr-xr-x 5 root root 4096 Dec 22 10:15 /path/to/databaseThe r(read), w(write), x(execute) characters show permissions. If the owner or group cannot write (w), that's your problem.
Determine which user your application or web server is running under:
# For web servers
ps aux | grep -E 'apache|nginx|www-data|php-fpm'
# For Node.js apps
ps aux | grep node
# For Python apps
ps aux | grep pythonNote the user in the first column (e.g., www-data, nobody, myappuser). This is the user that needs write access.
Once you know the user and group that should own the database directory, update ownership and permissions:
# Change owner to your application user (e.g., www-data for web servers)
sudo chown www-data:www-data /path/to/database/directory
# Grant read, write, and execute permissions to owner
sudo chmod u+rwx /path/to/database/directory
# Also grant write permissions to group if your app runs as a group
sudo chmod g+w /path/to/database/directoryFor most web applications, the safest approach is:
sudo chown -R www-data:www-data /path/to/database/directory
sudo chmod 755 /path/to/database/directory
sudo chmod 644 /path/to/database/directory/*.dbThe database file also needs to be readable and writable:
# Make sure the database file is readable and writable
sudo chmod 644 /path/to/database/directory/database.db
# Or if you want stricter permissions (owner only)
sudo chmod 600 /path/to/database/directory/database.dbIf the file is owned by root but your app runs as www-data, change ownership:
sudo chown www-data:www-data /path/to/database/directory/database.dbIf SQLite crashed or was interrupted, there might be leftover journal files:
# List all journal and temporary files
ls -la /path/to/database/directory/ | grep -E '\.db-journal|\.db-wal|\.db-shm'If you find them and the database is not currently in use, you can safely delete them:
rm /path/to/database/directory/*.db-journal
rm /path/to/database/directory/*.db-wal
rm /path/to/database/directory/*.db-shmDo NOT delete these files while the database is being accessed by a running application.
Test that writes now work. Using the sqlite3 CLI:
sqlite3 /path/to/database/directory/database.dbThen in the SQLite prompt:
CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT);
INSERT INTO test (name) VALUES ('test_entry');
SELECT * FROM test;
.quitIf these commands succeed, the permissions are now correct. Drop the test table if you created it:
sqlite3 /path/to/database/directory/database.db "DROP TABLE test;"Advanced notes
Web Server Scenarios: If your SQLite database is served by a web application (PHP, Node.js, Python, etc.), the web server user (typically www-data on Ubuntu/Debian, apache on CentOS, or _www on macOS) must have write access. Never run web servers as root for security reasons.
Docker & Containers: In Docker, ensure your Dockerfile sets proper permissions on the database directory. Use CHOWN in your Dockerfile or ensure the container runs with a user that has the appropriate permissions. Example:
RUN chown -R app:app /app/data
RUN chmod 755 /app/dataWAL Mode: If using Write-Ahead Logging (WAL) mode, SQLite creates additional .db-wal and .db-shm files alongside the database. These also need to be in a writable directory.
SELinux & AppArmor: On systems with mandatory access controls (SELinux or AppArmor), even correct file permissions may not be enough. Check your security policies: getenforce for SELinux or aa-status for AppArmor. You may need to adjust policies or labels to allow writes.
Read-Only Deployments: Some production scenarios intentionally keep databases read-only (e.g., replicas, archival). If this is intentional, open the database with the URI parameter ?mode=ro to avoid errors: sqlite3:///path/to/db?mode=ro
Frequently asked questions
- What does "SQLITE_READONLY_DIRECTORY" mean?
- SQLite needs to create temporary and journal files (such as -journal, -wal, and -shm files) in the same directory as your database file during normal operations. If the directory containing the database lacks write permissions, SQLite cannot create these essential files and will fail with the SQLITE_READONLY_DIRECTORY error. This happens even if the database file itself is writable—directory permissions take precedence.
- How do I fix "SQLITE_READONLY_DIRECTORY"?
- SQLite cannot write to your database because the directory containing it lacks write permissions. Both the database file and its parent directory must be writable for SQLite to function properly.
- What causes "SQLITE_READONLY_DIRECTORY"?
- Database directory has restrictive permissions (not writable by the application user) Database was created by a different user (e.g., sudo) and application runs as a different user Application runs as a web server user (www-data, nginx, apache) without directory write access
- Is the "SQLITE_READONLY_DIRECTORY" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚SQLite Official Documentation
- 📖sqlite.org - rescode(Official Docs)
- 📖sqlite.org - open(Official Docs)
- 🔗
- 🔗