Skip to content
All articles
Engineering8 April 2026·8 min read

Rotating an encryption key without rewriting your database

Rotation is only expensive when the key that encrypts data is the same key you are trying to change. One layer of indirection removes the whole problem.

Paycux engineering

Encrypting a column is straightforward. Changing the key afterwards is the part that gets deferred, usually until a compliance question forces it, at which point somebody discovers that rotation means decrypting and re-encrypting every row that has accumulated since launch.

It does not have to. The design that makes rotation cheap is older than most of the products that skip it, and adopting it costs an afternoon if you do it before the data exists.

Two keys, and only one of them touches data

Under envelope encryption, each record — or each tenant, or each file — is encrypted with its own data key. That data key is then encrypted by a key-encrypting key held in a managed store, and the wrapped result is saved next to the ciphertext. Reading means unwrapping the data key and decrypting; writing is the same in reverse.

Now rotating the key-encrypting key does not touch the data at all. You unwrap each data key with the old one and re-wrap it with the new one, and the volume of that work is proportional to the number of keys rather than the number of rows. A rotation that would have been a week of re-encryption becomes a job that finishes while you watch it.

  • Data key per tenant or per record; key-encrypting key in a managed store
  • Store the key identifier and version alongside every ciphertext
  • Rotating the outer key re-wraps keys, not data
  • Rotating an inner data key still requires re-encryption — scope it narrowly for that reason

Rotate the key that wraps keys and the work is proportional to your keys. Rotate the key that touches data and it is proportional to your data.

Version everything, and decrypt with either

Rotation is never instantaneous, so there is always a period in which some ciphertext is under the old key and some under the new one. Writing the key version into the record makes that period boring: decryption reads the version and selects the key, and no coordinated switch is required anywhere.

Without that field you are forced into try-the-new-key-then-the-old-one, which works until you have three generations and a subtle failure that looks like data corruption. A version is two bytes and it is what allows rotation to happen gradually.

The parts people forget

Backups are encrypted with the key that was current when they were taken, so retiring a key destroys your ability to restore anything older than the rotation. Keep retired keys available for decryption until every backup encrypted under them has expired, and write that dependency down where the retention policy lives.

The same applies to anything that copied the plaintext elsewhere: caches, search indexes, analytics extracts, message queues holding a payload for a retry. Rotation is a good moment to enumerate them, because a field you carefully rotate in the primary store and leave sitting in an index has not been rotated in any sense the question was asking about.

  • Retired keys stay available for decryption until the last backup under them expires
  • Enumerate the copies: caches, indexes, queues, extracts
  • Practise a restore after a rotation, not before — the untested path is the one that fails
  • Log rotations as audit events; a reviewer will ask when the last one happened

Everything here, already built

Sign-in, enterprise SSO, directory provisioning, roles and an audit trail behind one API. Start with the quickstart and have a working sign-in this afternoon.

Start selling to enterprise customers

Create an account, point sign-in at Paycux, and get back to the part of the product that is actually yours.