Choosing the Right Datastore for K3s: When to Stick with SQLite
Learn when to use K3s' embedded SQLite datastore versus external options like MySQL or etcd, including performance limits and verification steps for small clusters.
14 Apr 2026, 17:06 UTC

The Overhead of the Control Plane
Setting up a Kubernetes cluster often involves a frustrating trade‑off: you either accept the heavy resource overhead of etcd (the standard Kubernetes datastore) or you struggle with complex installation scripts for lightweight alternatives. For small‑scale projects, edge deployments, or local development, managing a three‑node etcd quorum is often overkill and consumes more RAM than the actual applications you intend to run.
The takeaway is simple: for clusters under 50 nodes with moderate write activity, K3s' embedded SQLite datastore provides a production‑ready persistence layer that eliminates the need for external database management without sacrificing the Kubernetes API surface.
How K3s Handles State with SQLite
By default, K3s uses SQLite, a C‑language library that implements a small, fast, self‑contained SQL database engine. Unlike etcd, which is a distributed key‑value store requiring its own cluster and consensus algorithm (Raft), SQLite stores the entire cluster state in a single file on the local disk.
This embedded approach means the k3s server process handles the database operations directly. There is no separate database process to monitor, no port to open for DB traffic, and no complex backup rotation for a separate stateful set. The cluster state is simply a file located at /var/lib/rancher/k3s/server/db/state.db.
Comparing SQLite to External Datastores
While SQLite is the default, K3s allows you to switch to external datastores like MySQL, PostgreSQL, or an external etcd cluster via the --datastore-endpoint flag. The decision usually comes down to write throughput and availability requirements.
| Feature | Embedded SQLite | External SQL (MySQL/Postgres) | External etcd |
|---|---|---|---|
| Setup Effort | Zero (Default) | Moderate | High |
| Resource Use | Very Low | Low (Offloaded) | High |
| Write Scaling | Limited (File Lock) | Moderate to High | High |
| HA Strategy | Single Node / Shared Disk | DB‑level Replication | Raft Consensus |
Verifying Your Datastore Configuration
If you have inherited a K3s cluster and aren't sure which persistence layer is active, you can verify it by checking the process arguments and the filesystem. Run these commands on the server node as a user with sudo privileges.
First, check if a custom endpoint was provided during startup:
ps -ef | grep k3s | grep datastore-endpoint
If this command returns no results, K3s is using the default embedded SQLite. You can further confirm this by checking for the existence of the database file:
ls -l /var/lib/rancher/k3s/server/db/state.db
Risk: Do not attempt to modify state.db using a manual SQLite browser while the K3s server is running. This can lead to database corruption or inconsistent cluster states.
The Performance Ceiling and Limitations
SQLite is highly efficient for read‑heavy workloads, but it relies on file‑level locking for writes. In a Kubernetes environment, every Pod update, ConfigMap change, or node heartbeat triggers a write. Once a cluster exceeds roughly 50 nodes, or if you are running highly volatile workloads (like frequent CI/CD deployments that create and destroy hundreds of objects per minute), the file lock becomes a bottleneck.
Furthermore, if you attempt to achieve High Availability (HA) by pointing multiple K3s servers to a single SQLite file on a network share (like NFS), you must ensure the filesystem supports NFSv4 or higher. Older versions of NFS have unreliable locking mechanisms that can corrupt the state.db file, leading to a total loss of cluster state.
Actionable Path Forward
If you are starting a new project, stick with the default SQLite. It simplifies your backup strategy to a simple file copy (provided the server is stopped) and minimizes your memory footprint. As your cluster grows toward the 50‑node mark, plan a migration to an external PostgreSQL or MySQL instance. Because K3s abstracts the datastore behind the same API, you can migrate your state to an external DB without changing how you interact with kubectl.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.