K3s’ Embedded SQLite: When the Default Data Store Is Enough—and When It Isn’t
K3s ships with an embedded SQLite database that removes the need for an external etcd, but the single‑writer lock and lack of replication limit its use to single‑node or low‑write workloads.
28 Feb 2026, 20:22 UTC

Why K3s Chooses SQLite by Default
K3s ships with an embedded SQLite database at /var/lib/rancher/k3s/server/db/k3s.db. This single file replaces an external etcd or MySQL cluster, giving you a zero‑config Kubernetes control plane that starts in seconds. The SQLite engine provides ACID guarantees, so a cluster restart recovers the API server state without any coordination service.
Where SQLite Shines: Dev, CI, Edge
- Development laptops – no extra containers, no network dependency.
- CI/CD pipelines – spin up a cluster, run tests, tear down; the database file is just another artifact.
- Edge nodes – limited disk, unreliable connectivity; a local file survives reboots and network partitions.
In all of these scenarios the write volume is modest (a few config maps, secrets, and pod specs per minute), well within SQLite’s single‑writer throughput.
The Concurrency and HA Ceiling
SQLite serialises all writes through a file‑level lock. When many controllers or operators update custom resources simultaneously, the lock becomes a bottleneck and API latency spikes. Moreover, SQLite cannot replicate across nodes; K3s deliberately disables multi‑node SQLite to avoid split‑brain scenarios. If you need a highly available control plane you must point K3s at an external datastore (etcd, MySQL, PostgreSQL).
Worked Example: Inspecting and Backing Up the SQLite File
Run the following on the K3s server node (requires root or sudo):
# 1. Verify the database exists
ls -l /var/lib/rancher/k3s/server/db/k3s.db
# 2. Open a read‑only SQLite shell
sqlite3 -readonly /var/lib/rancher/k3s/server/db/k3s.db ".tables"
# 3. Peek at a core table (e.g., pods)
sqlite3 -readonly /var/lib/rancher/k3s/server/db/k3s.db "SELECT name, namespace FROM k8s_pod LIMIT 5;"
# 4. Create a consistent backup while the server runs
sqlite3 /var/lib/rancher/k3s/server/db/k3s.db ".backup /tmp/k3s-$(date +%F).db"
Expected checks: the .tables command should list tables prefixed with k8s_. The backup file appears in /tmp and can be copied off‑node for disaster recovery. Risk: a sudden power loss during a write can corrupt the file; the backup step mitigates but does not eliminate that risk.
Mitigations and Migration Path
| Mitigation | When to Apply | Effort |
|---|---|---|
Scheduled .backup via cron | All single‑node clusters | Low |
| Mount the DB directory on a resilient volume (e.g., NVMe with power‑loss protection) | Edge devices with unstable power | Medium |
Switch to external etcd (--datastore-endpoint) | Multi‑node HA or write‑heavy workloads | High |
To migrate, stop the K3s server, copy the SQLite file to the new etcd cluster using the k3s etcd-snapshot tool (or the upstream etcdctl), then restart K3s with --datastore-endpoint=https://etcd1:2379,https://etcd2:2379,https://etcd3:2379. Verify with kubectl get nodes and kubectl get pods --all-namespaces.
Decision Checklist
- Is the cluster single‑node or a disposable test environment? → Stay with SQLite.
- Do you run many controllers that frequently patch CRDs? → Expect latency; plan for external datastore.
- Is the node subject to abrupt power loss? → Add automated backups or move to a replicated store.
- Do you need control‑plane HA across multiple servers? → SQLite cannot help; provision etcd.
Pick the simplest option that satisfies the highest‑priority requirement. For most developers and edge deployments the embedded SQLite is a pragmatic default; for production HA clusters it is a stepping stone, not a destination.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.