
Step by Step Guide to solve n8n SQLite cannot open database
Who this is for : Developers or DevOps engineers running n8n in containers or on‑premises who encounter SQLITE_CANTOPEN at startup or during workflow execution. For a complete guide on managing SQLite in n8n, including errors, performance, and migration, check out our n8n SQLite pillar guide.
Quick Diagnosis
| Symptom | Most common cause | One‑line fix |
|---|---|---|
| Error: SQLITE_CANTOPEN: unable to open database file | SQLite file missing or path wrong | Create the file or set an absolute path in N8N_DB_SQLITE_DATABASE_FILE. |
| Same error on start‑up (Docker) | Volume not mounted or permissions 0 / 600 | Mount the host directory and run chmod 660 /data/database.sqlite && chown 1000:1000 /data/database.sqlite. |
| Same error after a restart | SELinux/AppArmor blocking access | Add a policy rule or disable the security module for the n8n container. |
Quick actionable fix – run these three commands on the host before (re)starting n8n:
# 1. Ensure the file exists (creates empty DB if missing) touch /home/n8n/data/database.sqlite # 2. Give n8n read/write rights chmod 660 /home/n8n/data/database.sqlite chown 1000:1000 /home/n8n/data/database.sqlite # UID/GID used by the n8n container # 3. Point n8n to the absolute path echo "N8N_DB_SQLITE_DATABASE_FILE=/home/n8n/data/database.sqlite" >> .env docker compose up -d
1. Why n8n Can’t Open Its SQLite Database
n8n stores all runtime data in a single SQLite file (default: ~/.n8n/database.sqlite). The runtime calls sqlite3_open_v2; any of the conditions below makes the call return SQLITE_CANTOPEN.
| Root cause | How it manifests in n8n |
|---|---|
| File does not exist | ENOENT – “No such file or directory”. |
| Directory missing | SQLite cannot create the file because the parent folder isn’t present. |
| Insufficient permissions | EACCES – “Permission denied”. |
| Wrong path (relative vs absolute) | n8n looks in the wrong folder, often /root/ inside a container. |
| Docker volume mis‑mount | Host path not bound, or bind‑mount is read‑only. |
| SELinux/AppArmor blocking | Access denied despite correct POSIX permissions. |
| File locked by another process | Rare; surfaced as SQLITE_BUSY but sometimes as CANTOPEN. |
EEFA note: The official Docker image runs as UID 1000. Mismatched ownership is a frequent cause of this error. Learn how to handle SQLite connection and lock issues in n8n along with transaction troubleshooting tips.
2. Step‑by‑Step Verification Checklist
Run the following commands inside the container (docker exec -it n8n sh) to see the view n8n actually has.
| Check | Command / Action | Expected result |
|---|---|---|
| Database file exists | ls -l $HOME/.n8n/database.sqlite |
File listed (or create it). |
| Parent directory exists | dirname $HOME/.n8n/database.sqlite → ls -ld |
Directory exists and is writable. |
| UID/GID match n8n process | stat -c '%u %g' $HOME/.n8n/database.sqlite |
1000 1000 (or the UID/GID you run as). |
| Permissions allow read/write | ls -l $HOME/.n8n/database.sqlite |
-rw‑rw‑--- (660) or more permissive. |
| Env var points to absolute path | echo $N8N_DB_SQLITE_DATABASE_FILE |
Full path, e.g., /home/n8n/data/database.sqlite. |
| Docker volume is mounted | docker inspect <container> --format '{{ json .Mounts }}' |
Host source path listed, RW. |
| SELinux/AppArmor not blocking | getenforce (SELinux) / aa-status (AppArmor) |
Permissive/Disabled or policy allowing /data/**. |
3. Fix #1 – Ensure the SQLite File Exists
3.1 Create an empty database (if you’re starting fresh)
mkdir -p /home/n8n/data touch /home/n8n/data/database.sqlite
3.2 Initialise the schema (optional – n8n will auto‑create)
docker run --rm -v /home/n8n/data:/data n8nio/n8n \
node -e "require('n8n-core').Database.init('/data/database.sqlite')"
EEFA: Never copy a database from a different n8n version without running migrations (
n8n migrate).
4. Fix #2 – Correct File Permissions & Ownership
4.1 Set POSIX permissions (read/write for owner & group)
chmod 660 /home/n8n/data/database.sqlite
4.2 Set ownership to the Docker UID/GID (default 1000)
chown 1000:1000 /home/n8n/data/database.sqlite
4.3 Windows hosts – additional notes
On Windows, ensure the file is not marked *Read‑only* and that the Docker Desktop shared drive grants **Full Control** to the user running Docker. Understand how connection timeouts and database locks affect your SQLite workflows in n8n.
5. Fix #3 – Use an Absolute Path (or correct env var)
n8n reads the SQLite location from N8N_DB_SQLITE_DATABASE_FILE. Relative paths resolve inside the container, often to /root/.
# .env in your project root N8N_DB_SQLITE_DATABASE_FILE=/home/n8n/data/database.sqlite
If you prefer the default location, simply unset the variable; n8n falls back to ~/.n8n/database.sqlite.
EEFA: When running multiple n8n instances on the same host, always use unique absolute paths to avoid cross‑instance collisions.
6. Fix #4 – Docker‑Compose Volume Mapping
6.1 Service definition (core)
services:
n8n:
image: n8nio/n8n
restart: unless-stopped
6.2 Environment configuration
environment: - N8N_DB_SQLITE_DATABASE_FILE=/data/database.sqlite
6.3 Volume mount (host ↔ container)
volumes: - ./n8n-data:/data:rw # host folder must exist and be writable user: "1000:1000" # optional – forces UID/GID
6.4 Verify the mount from inside the container
docker exec -it n8n sh -c "ls -l /data/database.sqlite"
You should see the same UID/GID you set on the host. Check strategies to recover from transaction failures and other connection-related SQLite issues in n8n.
7. Advanced Troubleshooting
| Symptom | Diagnostic command | Interpretation |
|---|---|---|
Still SQLITE_CANTOPEN after steps |
docker logs n8n (full stack trace) |
Stack trace may reveal a *different* path (e.g., /tmp/…). |
| Error only on start, works after restart | Check docker-compose.yml for depends_on – volume may be mounted after n8n starts. |
Add depends_on: - db or restart: on-failure. |
| Error persists on **WSL** | wslpath -w /home/… – ensure path translation isn’t breaking. |
Adjust mount syntax for Windows‑style paths. |
| SELinux “Permission denied” | audit2allow -w -a → generate a policy module, then audit2allow -M n8n && semodule -i n8n.pp. |
Apply the generated module to allow the needed access. |
8. Production‑Grade EEFA Checklist
- Backup strategy – schedule daily backups:
sqlite3 /data/database.sqlite ".backup /backups/db-$(date +%F).sqlite"
- Read‑only fallback – during maintenance set
N8N_DB_SQLITE_READONLY=trueto avoid corruption. - Filesystem type – avoid network filesystems (NFS, CIFS) that lack proper file‑locking semantics.
- Health‑check – add a Docker health‑check that runs
sqlite3 $DB "SELECT 1"; alert on non‑zero exit. - Security – if SELinux/AppArmor is Enforcing, create a minimal profile that only allows
read/writeon/data/**.
9. Quick Recap
- Confirm the DB file exists (
touchif needed). - Set permissions to
660and ownership to the n8n UID/GID. - Use an absolute path via
N8N_DB_SQLITE_DATABASE_FILE. - Map the host folder correctly in Docker‑Compose (
:rw). - Check SELinux/AppArmor if the error persists.
Next Steps
If you’ve resolved the “cannot open database” error but still see sporadic failures, explore the “database is locked” child page for concurrency handling, or set up database backups as described in the production checklist above.
All commands assume a Linux/macOS host; adjust paths and user IDs for Windows or custom Docker users.



