---
title: "Encrypt a SQLite database in C#"
url: https://recursiveai.org/onelite/cookbook/encrypt-sqlite-database/
description: "Encrypt a SQLite database in C# with a runnable OneLite example, published NuGet packages and the actual console output."
version: "1.0.0"
---

# Encrypt a SQLite database in C#

**OneLite** is a free, open-source SQLite-compatible embedded SQL database for .NET from Recursive AI that reads and writes SQLite files. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneLite.Data) · [GitHub](https://github.com/recursive-ai-oss/onelite-csharp) · [Docs](https://recursiveai.org/onelite/docs/) · [Download example (.zip)](https://recursiveai.org/onelite/cookbook/encrypt-sqlite-database/encrypt-sqlite-database.zip)

Create a password-protected database with OneLite’s managed ADO.NET provider. Encryption is unavailable in browser builds.

```shell
dotnet add package RecursiveAI.OneLite.Data
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneLite.Data;
using System.Security.Cryptography;

string password = RandomNumberGenerator.GetHexString(64);
using var db = new OneLiteConnection(
    $"Data Source=demo-{Guid.NewGuid():N}.db;Password={password}");
db.Open();
using var command = db.CreateCommand();
command.CommandText = "CREATE TABLE notes(text)";
command.ExecuteNonQuery();
Console.WriteLine("Encrypted database created");
```

```text
Encrypted database created
```

Unzip [the example](https://recursiveai.org/onelite/cookbook/encrypt-sqlite-database/encrypt-sqlite-database.zip), then `dotnet run`.

## The full program

The snippet at the top generates a disposable demo password; retain your real password in your application’s secret storage so you can reopen the file. The full program creates a uniquely named database, inserts “Keep me”, reopens it with the same password and tries an incorrect password. A wrong key fails with `OneLiteDataException` and error 26, “file is not a database”. The project’s encryption review is its own review, not an external audit.

```csharp
using RecursiveAI.OneLite.Data;
using System.Security.Cryptography;

// A fresh random demo password, not a production secret.
string password = RandomNumberGenerator.GetHexString(64);
string path = $"encrypted-{Guid.NewGuid():N}.db";
var settings = new OneLiteConnectionStringBuilder
{
    DataSource = path, Password = password
};
using (var connection = new OneLiteConnection(settings.ToString()))
{
    connection.Open();
    using var command = connection.CreateCommand();
    command.CommandText = "CREATE TABLE notes(text); INSERT INTO notes VALUES ('Keep me');";
    command.ExecuteNonQuery();
}
using (var connection = new OneLiteConnection(settings.ToString()))
{
    connection.Open();
    using var command = connection.CreateCommand();
    command.CommandText = "SELECT text FROM notes";
    Console.WriteLine($"Right key: {command.ExecuteScalar()}");
}
settings.Password = "deliberately-wrong-demo-key";
try
{
    using var wrong = new OneLiteConnection(settings.ToString());
    wrong.Open();
    using var command = wrong.CreateCommand();
    command.CommandText = "SELECT text FROM notes";
    command.ExecuteScalar();
}
catch (OneLiteDataException error)
{
    Console.WriteLine($"Wrong key: {error.Message}");
}
```

```text
Right key: Keep me
Wrong key: SQLite Error 26: 'file is not a database'.
```

## Variations

To change the password, insert this after the full program’s successful read and before its wrong-key test. `quote()` turns the new password into a SQL string literal; PRAGMA does not accept a bound password directly. Retain the new password in your secret storage.

```csharp
string nextPassword = RandomNumberGenerator.GetHexString(64);
using (var connection = new OneLiteConnection(settings.ToString()))
{
    connection.Open();
    using var command = connection.CreateCommand();
    command.CommandText = "SELECT quote(@password)";
    command.Parameters.Add(new OneLiteParameter("@password", nextPassword));
    string quoted = (string)command.ExecuteScalar()!;
    command.Parameters.Clear();
    command.CommandText = "PRAGMA rekey = " + quoted;
    command.ExecuteNonQuery();
}
settings.Password = nextPassword;
using (var connection = new OneLiteConnection(settings.ToString()))
{
    connection.Open();
    using var command = connection.CreateCommand();
    command.CommandText = "SELECT text FROM notes";
    Console.WriteLine($"New key: {command.ExecuteScalar()}");
}
```

```text
New key: Keep me
```

## Related recipes

- [Use SQLite through ADO.NET](https://recursiveai.org/onelite/cookbook/sqlite-ado-net-csharp/)
- [Back up a SQLite database](https://recursiveai.org/onelite/cookbook/backup-sqlite-database/)

## The short answer

Install `RecursiveAI.OneLite.Data`, set `Password` before opening a new database, and use the same password each time you reopen it. The provider passes the key to OneLite’s page codec. The sample creates a new encrypted file; adding `Password` does not convert an existing plaintext database in place. OneLite can encrypt an existing plaintext file through `CipherFile.Encrypt`, but only when the source already reserves enough bytes per page and its page size matches the codec settings. The [whole-file transform documentation](https://recursiveai.org/onelite/docs/encryption/#whole-file-transform) describes preparing that layout before conversion. An ordinary plaintext file without that reserved space is not accepted by this transform; neither opening it with a key nor this rekey variation is a general plaintext-file conversion.

## Can a SQLite database be encrypted?

OneLite can encrypt the database file, rollback journal and WAL when the database is opened with a key. Its provider exposes that key through the `Password` connection-string property. The [encryption documentation](https://recursiveai.org/onelite/docs/encryption/) describes the page codec, settings and error behavior.

That is encryption at rest, not an access-control system for your SQL calls. Once your application has opened the database with the correct key, it can read and change rows normally. Do not log the connection string or print the password. The example prints only the stored row and the deliberately failed read.

The snippet generates a fresh demo password and a unique file name on every run. It deliberately does not persist the password, so that file is not a useful long-term store after the process exits. In an application, obtain a retained password from your secret-management system and keep the same database path. The full program keeps the password in memory just long enough to demonstrate reopening the database.

## How do I encrypt a SQLite database in C#?

Use `OneLiteConnectionStringBuilder` when the password comes from outside your code. Its `Password` property avoids treating connection-string punctuation in the password as configuration. Open the resulting connection, create your schema and insert rows through ordinary commands. Encryption is below the SQL layer; the table does not need special encrypted column types.

The full program closes its first connection before opening a second with the same settings. That is the important distinction between reading rows in an already-open connection and demonstrating that a file can be reopened with its key. The wrong-key attempt then opens the same file with a different password and attempts a query.

For the default encrypted format, a wrong key, a wrong codec setting or a plaintext file opened as encrypted fails on the first page with `SQLITE_NOTADB`, “file is not a database”. That message alone does not distinguish these causes. Check the path, the secret and the format settings before treating it as evidence of file damage. Later-page authentication failures have a different corruption error.

## What does SQLite encryption at rest protect?

The codec encrypts page contents using AES-256-CBC and authenticates them with HMAC. Format parameters are not all stored in the file; the opener must know the matching settings. This recipe stays with the defaults rather than promising interoperability with every encrypted SQLite format. Follow the documented format settings when exchanging encrypted files.

The browser build has no supported AES implementation for this codec and rejects encryption. Managed key handling also has a narrower guarantee than erasing every possible copy of a secret: the library clears its own pinned key arrays on disposal, but caller strings, runtime copies, swap and core dumps are outside that guarantee. Dispose connections promptly and avoid unnecessary password copies. A retained key needs its own protection and recovery plan; losing it is not fixed by keeping another copy of the encrypted database.
