Why the KeePass format should be based on SQLite

2026-02-2413:08151114mketab.org

Table of ContentsKeePass has long been the gold standard and darling of the tech world, earned through its unrelenting commitment to security, stability, and data sovereignty. However, the XML format…

Table of Contents

KeePass has long been the gold standard and darling of the tech world, earned through its unrelenting commitment to security, stability, and data sovereignty. However, the XML format which the KDBX file format has been predicated on 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. An 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 an 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. An SQLite based format facilitates this better than the kdbx format, and only requires a one time hurdle for long-term format stability 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 two heavily structured format.

  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 an 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:10

xkcd comic titled: ‘How Standards Proliferate’

Discussion on Hacker News

References


Read the original article

Comments

  • By thayne 2026-02-2420:212 reply

    > no matter how small the edit was, the entire file gets rewritten

    SQLite doesn't fix this, because you would still need to encrypt the whole file (at least with standard sqlite). If you just encrypted the data in the cells of the table, then you would expose metadata in plaintext.

    SQLCipher does provide that, but as mentioned by others, it isn't quite the same thing as sqlite, and is maintained by a different entity.

    > 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.

    That isn't a limitation of xml, and could also be an issue with sqlite. The real problem here is if clients fail if they encounter tags or attributes they don't recognize. The fix here is for clients to just ignore data it doesn't know about, whether that is xml or sqlite.

    The complaints about compatibility between different implementations would be just as bad with sqlite. You would still have some implementations storing data in custom attributes, and others using builtin fields. In fact it could be even worse if separate implementations have diverging schemas for the tables.

    > Governance Issues

    None of this has anything to do with sqlite vs xml. It is a social issue that could be solved without switching the underlying format, or remain an issue even if it was changed.

    • By ktimespi 2026-02-255:282 reply

      SQLite has its own closed-source page-level cipher format, so I don't think this argument makes sense.

      https://www.sqlite.org/see/doc/trunk/www/readme.wiki

      A weakness though, again, is that this is closed source...

      • By wps 2026-02-255:362 reply

        The biggest weakness is the cost. Each client would have to purchase an expensive license. The source code is provided upon purchase though, but essentially destroys the ability to build a client from source due to the compiled binary distribution.

        • By ktimespi 2026-02-256:381 reply

          yeah, that was the point that I was making. Although I do wonder if encrypting the whole file is necessary.

          • By wps 2026-02-256:43

            I really doubt it. I have not seen any evidence to suggest that there are irreconcilable issues with SQLCipher's page level encryption over a flat file. Codebook, Enpass, Signal, and a ton of other important clients use it just fine.

      • By thayne 2026-02-2517:40

        That isn't really an option for an open source project like keepass(xc)

    • By rustyhancock 2026-02-257:531 reply

      I'm not sure why it's a concern that the whole file needs a rewrite.

      Naiively perhaps I thought that was helpful with solid state storage because it means that old data is trimmed faster?

      It mentions it near the entire file being in memory but that seems a dubious concern. If the key is in memory the entire file can be comprised either way. Nothing can really stop that if you have access to the programs memory.

      • By thayne 2026-02-2517:45

        It's an issue if you have a really big password database, for example because you are storing large attachments in there. Especially if you are also syncing the file over the network. Also if your file is multiple GB, having it all in memory is an issue because of the amount of memory used.

        That isn't really how keepass is meant to be used, but apparently people do use it this way.

  • By advisedwang 2026-02-2418:242 reply

    > 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

    Perfectly possible with XML too

    > An SQLite based store is one of the most tested and optimal formats for document and application storage

    It's optimized for things that largely don't matter for password storage. The testing is admirable, but there's no issue of keepass clients crashing or corrupting data so again, not very relevant (probably because of low concurrency, simple writes etc).

    > 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

    You don't need a technical change to solve this. In fact, a fork that would fracture clients is the last thing you need when making governance changes.

    > So many quality of life features can be added where the old schema disallowed it

    All of the features they list can be achieved with an XML format. The format isn't what's holding them back.

    • By hollow-moe 2026-02-2419:121 reply

      I don't know if this could count as "corrupting": I made the mistake of syncing my keepassxc database to my macbook with finder webdav client (nextcloud backend) it read the file alright but when I tried to write a new secret it helpfully wrote an empty file in place, wiping nextcloud file versions in the process. Thankfully, Nextcloud was smart enough to move the previous file in the trash bin and I could restore it. It seems keepassxc "save" procedure here was to delete the old file and replace it with a new one and something went catastrophically wrong in the process ? Looking at the settings there's is a parameter for this method for particular circumstances but I didn't enable it back then. Now I just have a second database only on this mac synced to icloud and never letting it near my nextcloud again.

      • By advisedwang 2026-02-2421:521 reply

        I actually had a similar thing happen with gvfs-fuse (Google drive). It was a bug in gvfs using the quota usage of a file as it's file size (because libgdata didn't provide a method to get file size), but I was using a file shared to me so it had zero quota usage.

        All of which is to say I would bet on something in the webdav-nextcloud line being at fault instead of keepassxc.

        • By hollow-moe 2026-02-251:15

          I sync'd this file using various means on different platforms, nextcloud apps on windows using virtual files and android with Storage Access Framework cloud integration, and on linux with rclone and somehow never had such a catastrophic issue

    • By ctoth 2026-02-2419:093 reply

      > All of the features they list can be achieved with an XML format.

      Not writing the entire database on every save?

      • By layer8 2026-02-2420:251 reply

        Not a problem for XML per se (you can work with byte positions, and with fixed-size blocks to avoid resizing/relocation), but in the case of KDBX there is the issue that it is encrypted as a whole. Not encrypting as a whole, on the other hand, risks leaking more information about the contents, like you can see which parts/how much changed between one update and the next.

        • By kbolino 2026-02-2420:581 reply

          Whole-file encryption with authentication is also more tamper-resistant. Basically the only thing an adversary can get away with there is rolling back the entire file to a previous version.

          Whereas, any incrementally encrypted format has the additional risk of piecewise manipulations. For example, while SQLCipher authenticates each page, it doesn't authenticate the entire file, allowing for pages to be deleted, reordered, or duplicated (though duplication is easy to detect since each page has its own IV). The end result will generally just be a corrupted database, which will probably get detected by PRAGMA integrity_check, but compared to KDBX, this will not be detected by default nor is it guaranteed to be detectable at all.

          • By WorldMaker 2026-02-2421:41

            Another in place option is AES-encrypted ZIP. ZIP has the benefits that the Directory at the end of the file can also include piecewise metadata for full file validation.

            A part of me wonders if the only real upgrade needed for the next "large file" KDBX relative format is from a GZIP stream of the XML plus attachments to a ZIP container of the XML with attachments in some folder structure combined with the choice of a good piecewise (modern) encryption for the ZIP container. (That is taking more cues from 7zip than from classic, now broken password-encrypted ZIP files.)

            (Though as someone who tries to keep my KDBX files small, I think I'd still prefer the option of a whole-file encrypted format.)

      • By rlpb 2026-02-2423:16

        I actually prefer this. It's how most user-facing file formats work. KDBX in particular is often used in conjunction with syncing software, and I don't want a half changed file to sync and then the connection to be lost. The usual paradigm of "write new file then move and replace over old file" works more safely for atomic changes.

      • By advisedwang 2026-02-2420:13

        That's not a feature, that's an implementation detail.

  • By ifh-hn 2026-02-2419:41

    The schema issues aren't solved by moving to sqlite, or the proposed solution is doable with XML too. I can see the same thing with the attributes (some described it as a shadow schema) happening in an attributes table just as easily. And in my experience relational schemas are a lot harder to modify than a document schema like XML.

    EDIT: also you don't need to have just one password vault and I'd say you probably shouldn't, separate entries also assist with separation of concerns. This last adds a little overhead but is a reasonable workaround.

    However on the whole I like sqlite for app persistence. It can, however, leak data (forensically) if not managed properly.

HackerNews