SQLite is the Evolutionary Perfection of the KeePass KDBX Format

Mohammed Ketab

2026-02-22

KeePass has long been the gold standard and darling of the tech world due to its unrelenting commitment to security, stability, and data sovereignty. However, the XML format on which the KDBX file format has been predicated since 2007 has become a persistent friction point for developers and users in the adoption of modern security and convenience features.

The Problems with KDBX

Let us first start by explaining what a KDBX (4.1) file actually is. 1 Barring the technicalities, a KDBX file is an encrypted & authenticated gzipped XML file which contains the typical fields you may expect of a password manager. Attachments are stored as binary data (the old KDBX 3 format used to base64 encode the files), while custom icons are stored as base64 strings within the XML file. Important to note is that every time a KDBX file is updated, no matter how small the edit was, the entire file gets rewritten. The entire file is also loaded into memory. Perhaps the most relevant part of the spec to this post are the TProtectedString and CustomData references, which, respectively, are the user-facing custom attributes, and non-user-facing plugin or app data.

Brittle Schema

The primary issue is that new features cannot be added natively to the XML tree without causing breaking changes for older clients or third-party clients which have not adopted the change yet. This has led to significant problems implementing new standards that were solved ad hoc, in a backward compatible manner using the custom attributes.

Prior to any KeePass client supporting TOTP, third-party KeePass Proper plugins implemented the feature by adding a TOTP entry to the custom attributes. The problem was that different plugins used different field names and stored the generation parameters differently, making them mutually incompatible. Certain mobile clients then began to include support for the most common plugins’ TOTP format. Then, KeePassXC implemented it into the main client, opting for a standard otp URI that was interoperable with most standalone authenticator apps. Like the plugins, this otp field was stored in the attributes. When KeePass Proper came around to implementing TOTP support natively, Dominik Reichl, the founder, disliked the URI format due to parsing and UX issues.2 This caused another discontinuity, where KeePass Proper used TimeOtp-Secret while the community forks and plugins mostly used the previously described otpauth format.3

Passkey support is another example where complex data was shoehorned into the custom attributes rather than being treated as a first class citizen. StrongBox was the first client to implement passkey support4 and actively collaborated with KeePassXC to ensure compatibility for KeePassXC’s future release. However, there was a brief period of incompatibility between the two programs, which was promptly resolved.5 Passkeys litter the user-facing attributes with five different entries, which makes it difficult to select entries which actually matter to the user.

Further adding to the clutter, some mobile clients add attributes which associate app IDs to entries for autofill. Here is a particularly egregious entry I have which best demonstrates this issue:

KeePassXC Additional Attributes menu showing fields for Dream, Drink, Game, five KPEX Passkey identifiers, and OTP.

The first three security question attributes are the only ones that are mine!

The lead developer of KeePassXC summarizes the whole issue well:

I am trying to avoid implementing a multitude of “minor” interim solutions. That creates significant code bloat with exceptions and workarounds depending on which version of the standard you are on. The myriad of plugins made for KeePass over the years demonstrates why this is not a good thing. They all made their own unique standards.

Modern security features should never need to get in the user’s way, and should never have the potential for a user to be locked out of reading it simply because their mobile client understands otp while their desktop client understands TimeOtp-Secret. In practice, the different clients just support both, but this is an undue technical burden which could be solved with explicit and special support in the schema to begin with.

Storage Inefficiencies

As mentioned, KDBX files keep all custom icons as base64 in the XML file. This causes a roughly 33% jump in file size per icon. It also massively increases memory usage and decreases access and save speed, especially on mobile, since everything needs to be loaded into memory. Further, since the whole file is rewritten on every edit, there can be problems if the program crashes or power halts mid save. Also, the chance of irrecoverable corruption on network shares or cloud services is high, which is why several KeePass clients offer alternate saving methods which involve backup files.

Although I quite agree with Dominik on general encrypted file storage being far out of scope for a password manager, I have noticed that many KeePass users report using the database as an all-purpose secrets manager. Users attach unoptimized passport, ID, and all sorts of important scans to their password database all the time. Paired with custom icons for every entry, the most dire cases involve horrific databases which have bloomed to 500+MiB. I recognize that this is a severe outlier, but many users have databases that fall in the range of 10-100MiB (Just a few PDF attachments can get you in this range), which is well in the realm of super slow mobile unlocking, and getting OOM errors during autofill events.

Just to emphasize that I have no horse in this specific race; my personal database sits at around 50KiB. However, I still believe that users should be able to conveniently store a set of various secrets in their password database rather than have to use a variety of encryption tools which are often not as user or mobile friendly as the KeePass ecosystems.

Governance Issues

Dominik Reichl has maintained this format and its iterations for longer than I have been alive. So everything I say should be taken with a grain of salt and with utter respect to his efforts. I sincerely appreciate the immense focus on conservatism and compatibility in many of his quite wise considerations.

However, this attitude is fundamentally at odds with being able to expand the features of the format to better accommodate modern use cases and development practices. To quote a KeePassXC maintainer in response to Dominik bumping the minor version with small changes from the wider discussion:6

I’d be happy if we could somehow sketch out what a KDBX 4.1 and/or 5 should look like together. I don’t want to add too much bureaucracy to the process, but Dominik just picking or rejecting things and informing us about it, seems kinda one-way (no offence in any way, I appreciate the communication)

The somewhat interconnected shadow schema that has developed across the various forks is just not sustainable. It has led to a various matrix of incompatibilities that could have otherwise been avoided if the entire format had been developed together. KeePassXC by far has the most users and is under the most active development. If we were to combine the four popular mobile clients in this count, they far outweigh the userbase of the original KeePass. This is to say that it is unfair and impractical for the vast majority of users within the KeePass ecosystem to be unilaterally subject to the original program’s decisions regarding the file format. It also leads to a first mover advantage, where whichever major client implements some sort of feature that their users request, that features namespace then has to be accounted for in the other clients.

In cloud native platforms like BitWarden, these issues are non-existent, as the company can arbitrarily change their schema completely transparently to its users. With a local first ecosystem like KeePass, you cannot just update every user’s file at once. A modern, open democratic spec is a necessary step for continued practical development.

Why SQLite with SQLCipher is the Right Answer

A final breaking refactor to SQLite has the potential to solve all three major problems. Let’s go in order.

  1. Devising a new schema based on SQLite would allow for current features that are being jerry-rigged into the attributes to have their own real place in the database, rather than clogging the user-facing fields. It also ensures that if in the future, some weird authentication method were to come out, no breaking changes would be needed. You simply would add a table to accommodate it, and old clients would simply not support the feature and just load the database without it. Of course, a warning would be shown to the user if somehow their database uses new features on an old client. Devising it together would allow for all the weird program specific fields to be scrapped in favor of a unified location for things like app associations and autofill histories. This would be the codification of the years of “interim features” and fixes piled on by the forks.

  2. A SQLite based store is one of the most tested and optimal formats for document and application storage. The creator of SQLite writes extensively on the matter,7 so I will not cover all the benefits, just the specific ones that address the problems I brought up. Database sizes could get dramatically smaller due to icons being stored as blobs. Memory usage would significantly drop for larger databases, as SQLite does not need to load the entire file into memory during opens or saves. This allows for better use of the KDBX file as a personal catch-all secrets manager for those who use it as such.

    Many file sharing tools, sync tools, and some cloud platforms (Dropbox for instance) support delta syncs with block-level delta compression. For example, if you were to change a word in a text file, you need not reupload the entire file, just the small part that changed. This is not possible with a flat encrypted blob like a KDBX file. However, with SQLCipher, since all pages are encrypted, changing one password only changes its page. So rather than risking sync issues uploading your 20MiB KDBX file on every minor change, you can upload just the 4KiB or so comprising that data. This holds true even with SQLCipher’s encrypted pages. Additional benefits include:

    • There exist far more tools to recover a SQLite database than there are to recover a KDBX database.
    • Easier merges via sqlite3_changeset and row level merges rather than entire file conflicts.
    • Easier developer experience through implementing complex searches via SQL queries rather than re-implementing entry search across every client.

    Just like the crab is the ultimate form of crustacean life,8 a relational backend is the natural optimum for complex password management, and SQLite even more so for local management. The developers of the SQLCipher themselves created CodeBook, which is a password manager based on SQLCipher, showing their immense trust in it as a storage format. Enpass is another such example. It just works.

  3. A switch this big is a major chance to fix the governance structure and align it more with a democratic consortium than a benevolent-dictator-for-life style of project management. This would also probably warrant a new file extension to signal how incompatible this change is, perhaps .kp?

  4. So many quality of life features can be added where the old schema disallowed it. Things like a granular global history and versioning, more complex group relations, etc. Long requested features such as specific entry types for payment cards, or anything else that does not neatly fit into the username and password paradigm. Keeping my credit card number in the password field with several attributes is just not satisfying. Other password managers (BitWarden, CodeBook) have no problem implementing features like this. In fact, CodeBook supports completely arbitrary templates and does not place on restrictions on how the user organizes their data. Some KeePass client developers have even hinted at the fact that SQLite would be able to do a lot of what they want!

Anticipated Rebuttals and their Refutations

  1. The transaction safety and rollback features of SQLite are against the one-file philosophy of KeePass. To which I respond: The auxiliary files (WAL, SHM, etc) are not necessary to retain the robust transactions and safety of the file. You can easily VACUUM INTO on every save or set PRAGMA journal_mode = DELETE; or use one of the many other ways to operate the database as a single file and be on your way. You can also just use a rollback journal, which does create a temporary file which is deleted right after the transaction (pretty similar to the existing save features in clients, but does not duplicate the entire database). Also, many KeePass clients inherently keep around one or more backup files to avoid corruption issues while saving.

  2. Backwards compatibility. Look, there are people still using KDB files. There are people still using Excel workbooks. God forbid, there are people using Post-It notes. The reality is, the majority of users want modern features. A SQLite based format facilitates this better than the kdbx format, and only requires a one time hurdle for permanent backward compatibility after. This is not dissimilar to the jump from KDB to KDBX (which yielded far less benefit for a breaking change). The migration process would also be frictionless for users, it is a simple data map between probably the two easiest formats of all time.

  3. Preservation and Human Readability. Ultimately, both formats in their end state are generally encrypted blobs. This state is not human readable at all. The formats must be opened in plain text, which is severely discouraged except in the case of a quick export. I have nothing against keeping an XML export format, as it is probably easier for other random password managers to parse and is more readable in a text file than a SQLite dump. SQLite is also recognized for its long term preservation value by the Library of Congress.

  4. Users have the freedom to open the DB in insecure views that don’t protect the memory space like DB Browser for SQLite. I don’t consider this a huge issue, as users can also export their plaintext KDBX file to CSV or XML and view it just fine. Users also routinely do dumb things like using a poor master password or lack backups. What the user does with their file is ultimately up to them.

  5. Adding a SQL engine is too heavy of a dependency. I heavily disagree, there are so many apps that do far less than any KeePass client which use sqlite. The contacts app on your phone that does absolutely nothing but shows, adds, and deletes contacts (analogous to a primitive password store) bundles SQLite. It is also one of the most audited and mission critical pieces of software on the planet, with 100% branch test coverage. Used in the field (well, mostly in the sky) by NASA, AirBus, and everyone else you could imagine.

  6. Metadata leakage. There should not be a substantial difference between the flat KDBX file and an encrypted SQLCipher database in terms of forensic analysis. SQLCipher uses fixed page sizes, so file size growth is less linear than a KDBX file. If it is good enough for Signal and the previous password managers I mentioned, it is probably good enough for KeePass. Also, I would like to mention that Pass; the Unix password manager and its derivatives overtly leak data about how many entries you have and to which service they belong (No shade though, I understand the arguments). A SQLCipher implementation would never come close to that level of information leakage, and yet Pass is considered completely fine.

Call to Action

KeePassXC is already the de facto leader of the space, I urge the developers to focus their efforts on declaring the spec and including the major mobile developers in the discussion from start to finish. There seems to have been an attempt 9 to develop a new spec on the KeePassXC GitHub organization that has not seen an update in 8 years!

As for users, if the arguments persuaded you, voice your support in the relevant public development forums and channels.

My cursory (lol, get it?) understanding may be incorrect. Please feel free to call out any technical assumptions or errors I may have made!

Also, before anyone beats me to it:

xkcd comic titled: ‘How Standards Proliferate’

References


  1. Official KDBX Specification ↩︎

  2. Dominik on OTP ↩︎

  3. Dominik on OTP 2 ↩︎

  4. StrongBox Passkey Announcement ↩︎

  5. StrongBox-KeePassXC Passkey Incompatibility ↩︎

  6. Issue 4317: Democratic Governance Sentiment ↩︎

  7. SQLite As An Application File Format ↩︎

  8. Carcinisation ↩︎

  9. KeePassXC-Specs ↩︎