Upgrading to SQLCipher 4


The recent release of SQLCipher 4 introduces many new performance and security enhancements for applications that use SQLCipher for secure local data storage. However, the introduction of new default algorithms, increased KDF iterations and a larger page size means that SQLCipher 4 will not open older databases by default.

This document provides guidance on the upgrade options available to applications that have previously integrated SQLCipher versions 1 through 3.

Option 1: Database File Migration

SQLCipher provides a very convenient way to perform an “in place” migration of a SQLCipher database using PRAGMA cipher_migrate. This does all the work of updating the database file format with a single SQL statement. After migration the database will use all of the latest default settings so an application can immediately benefit from improved performance and security.

PRAGMA cipher_migrate be run a single time immediately after the key is provided (i.e. via sqlite3_key() or PRAGMA key in order to upgrade the database. This would normally occur on the first run after the application is upgraded to perform a one-time conversation.

After the migration is complete the application will no longer need to call the command again on subsequent opens.

PRAGMA key = '<key material>';
PRAGMA cipher_migrate;

The PRAGMA will return a single row with the value 0 after successful completion of the migration process. The migrated database will remain open and use the same filename.

Option 2: Backwards Compatibility

The second option is to use the new SQLCipher 4 library, but use all of the SQLCipher 3 (or earlier) settings. This requires an application to execute PRAGMA statements immediately after keying the database that will match the settings originally used to create the database.

Starting with SQLCipher 4.0.1, you can use the new cipher_compatibility feature. Passing values 1, 2, or 3 to the PRAGMA will cause SQLCipher to operate with default settings consistent with the respective major version number for the current connection. For example, the following will cause SQLCipher to treat the current database as a SQLCipher 3.x database:

PRAGMA cipher_compatibility = 3;

It is also possible to use the similar cipher_default compatibility PRAGMA to set the value for the lifetime of a process before key operations are invoked.

Applications are also free to explicitly manage the low-level page size, KDF, and algorithm settings. This option is more verbose, but works effectively the same way. The appropriate settings vary by the SQLCipher version used previously:

SQLCipher 3

PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 64000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;

SQLCipher 2

PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;

SQLCipher 1

PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
PRAGMA cipher_use_hmac = OFF;

When using legacy settings, the library will be operating in a compatibility mode with a previous release. Thus, an application will not be taking advantage of all the security improvements available in the new version. Instead the application will function with the same level of security as the original SQLCipher version.

It is important to note that since no migration is occurring, compatibility statements must be executed every time a database is opened. It is, however, possible to set process-level defaults using the cipher_default_ versions of these PRAGMAs (e.g. PRAGMA cipher_default_kdf_algorithm). This will change the default settings for the lifetime of the process. Please refer to the SQLCipher API for a full list of available settings.

Option 3: Custom Export Migration

When an application uses a custom configuration or non-default settings it is possible to use the sqlcipher_export() convenience function for fine-grained control over the migration process. The general procedure for using sqlcipher_export() follows.

  1. Open a connection to the existing database and set the appropriate backward compatibility PRAGMAs as described in Option 2.
  2. Attach a new encrypted database, which will use the new settings by default.
  3. Set any custom PRAGMAs for the new attached database (optional).
  4. Call sqlcipher_export() to “copy” the data from the main database to the new attached database.
  5. After export, detach the new database, and close the main database connection.
  6. Re-open the new database, optionally deleting the original database and/or renaming the new database as appropriate.

The following example demonstrates the statements required to migrate a SQLCipher 3 database using sqlcipher_export(). At the end of the process the migrated database will be named sqlcipher-4.db.

PRAGMA key = '<key material>';
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 64000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
ATTACH DATABASE 'sqlcipher-4.db' AS sqlcipher4 KEY '<key material>';
SELECT sqlcipher_export('sqlcipher4');

Choosing the Right Approach
Applications are free to select an upgrade approach that most closely meets their requirements. However, the recommended approach is to use Option 1 to take advantage of new features while minimizing the complexity of the application code required for migration.

Problem with sqlcipher on iOS 12
Upgrading to SQLCipher 4 for .NET applications using the SQlite-net API
Issue opening encrypted database in swift that was created in objective c
File is not a database:
File is not a database:
File is not a database:


What ciphers are supported in SQLCipher 4? 3 at some point supported aes-256-cbc, but it seems to me that 4 uses aes-256-cfb? Or am I mistaken?

If so, how does one read an old database with aes-256-cbc, since the “cipher” PRAGMA is no longer available?



Thanks for using SQLCipher.

aes-256-cbc is still the cipher used by SQLCipher 4, which is referenced on the design page under Security Features. As you mentioned PRAGMA cipher is now fully deprecated and will be a no-op if you attempt to call it with a different cipher.

but it seems to me that 4 uses aes-256-cfb?

Where are you seeing that?


specifically in Android, at which point do we have to call

because by the moment I call getWritableDatabase(password) it crashes.


Hi @Gerardo_Robledo

The SQLiteOpenHelper allows you to provide a SQLiteDatabaseHook via this constructor which will allow you to run the PRAGMA cipher_migrate command.


Got it.
I used the postKey method to call PRAGMA cipher_migrate command.



Hey @Gerardo_Robledo

could you share your solution? My current approach looks like this:

super(context, DATABASE_NAME, null, DATABASE_VERSION, new SQLiteDatabaseHook() {
        public void postKey(SQLiteDatabase database) {
            database.rawQuery("PRAGMA key = `" + THE_SECRET_PASSWORD + "`; PRAGMA cipher_migrate;", null).close();

        public void preKey(SQLiteDatabase database) {


Nevertheless I get the same error as before:

net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;

Thanks for your help!


Hi @ifi_tubaf

You don’t need to execute PRAGMA key in the postKey event, the database will be keyed when you call getWritableDatabase(...). Here is an example of applying the PRAGMA cipher_migrate command and checking the result.


Hi @ifi_tubaf
I’m using Kotlin so it looks something like this:

     val hook = object: SQLiteDatabaseHook {
            override fun preKey(database: SQLiteDatabase?) {


            override fun postKey(database: SQLiteDatabase?) {
                    database?.rawExecSQL("PRAGMA cipher_migrate")            

but I would recommend to check the example that @developernotes mentioned.