Applications and operations
SQLite permissions live outside the database
Understand why SQLite has no user permissions: GRANT and REVOKE are not available because the database is a single file, so handle access in your app.
If you come from MySQL or PostgreSQL, one of the first surprises with SQLite is that there is no GRANT or REVOKE. You cannot create database users, assign read-only roles, or limit one connection to a single table.
That is not a missing feature waiting for a future release. SQLite simply cannot do it, because the whole database lives in one file on disk.
The file is the boundary
PostgreSQL keeps data inside a server process. Clients connect over the network, authenticate with a username and password, and the server decides what each session may read or write.
SQLite stores everything in a single file such as notes.db. Your application opens that file through a library. There is no server in the middle, and no session layer where permission checks could run.
Anyone who can read the file can read every table. Anyone who can write the file can change or delete anything inside it. The operating system decides who gets file access, not SQLite.
You can see this yourself. Open the database in the shell:
sqlite3 notes.db
SELECT * FROM notes;
There is no login step. If the shell can open the file, it can query every row.
Where permissions actually live
If your product needs per-user access control, you build it in application code. A typical web app stores a user_id on each note and checks ownership before returning or changing a row:
const note = db.prepare(
'SELECT id, title FROM notes WHERE id = ? AND owner_id = ?'
).get(noteId, currentUser.id)
if (!note) {
throw new Error('Not found')
}
That check runs in your API layer, not inside SQLite. A script with direct file access bypasses it entirely.
The same rule applies to backups. Copying notes.db copies every user’s data. Treat the file like a secret, restrict filesystem permissions, and never expose it through a public download URL.
When a server database makes more sense
SQLite fits when one trusted application owns the file on one machine. If several independent services need different access levels to the same data, or if untrusted users must connect directly to the database, PostgreSQL or MySQL is the better tool.
That trade is intentional. SQLite trades server-side permission models for zero setup and a database that fits in your pocket. Know which side of the line your project sits on before you commit to the file.
Lesson completed