Readyset Docs
Configurations

User Management

Readyset keeps its own set of users that are allowed to authenticate with it. That set has two stages in its life: it is seeded from command-line flags the very first time a deployment starts, and from then on you manage it with SQL against a running Readyset, with no restart and no dropped connections.

Bootstrap on the first startup

On a deployment's first startup, Readyset seeds the allowed-users set from two places:

  • The user in --upstream-db-url, so the credentials Readyset already has can also be used to connect to it.
  • --allowed-users (env ALLOWED_USERS), a comma-separated list of username:password pairs.
readyset --upstream-db-url postgresql://readyset:<password>@db.internal/app \
         --allowed-users 'alice:<password>,bob:<password>'

That start accepts readyset, alice, and bob.

Seeding happens once. Readyset then stores the set and reads it from storage on every later start, so editing --allowed-users or pointing --upstream-db-url at a different user has no effect on who may authenticate. After the first startup, use the commands below.

Managing users at runtime

Connect to Readyset as any allowed user and run:

ALTER READYSET ADD USER 'carol' PASSWORD 'carolpw';
ALTER READYSET MODIFY USER 'carol' PASSWORD 'rotatedpw';
ALTER READYSET DROP USER 'carol';

Each command is stored before it returns, so it survives restarts, and takes effect on the next connection attempt: an added user can connect right away, a rotated password is required immediately, and a dropped user is refused. A dropped or rotated user's connections that are already open are not closed; the change applies when they reconnect.

ADD USER fails if the user already exists; MODIFY USER and DROP USER fail if it does not. The user derived from --upstream-db-url cannot be modified or dropped, since that identity backs Readyset's own connection to your database. All three commands require authentication to be enabled, so they are unavailable under --allow-unauthenticated-connections.

A user in Readyset also needs to exist in your database with the same password. Readyset opens each session's connection to your database with that session's own credentials, so ALTER READYSET ADD USER is a companion to a CREATE USER upstream, not a replacement for it.

Rotating a password without downtime

Changing a password with MODIFY USER normally requires new connections to begin using the new password immediately. To allow the old password to remain valid during a transitional period to the new password, perform:

ALTER READYSET MODIFY USER 'carol' PASSWORD 'rotatedpw' RETAIN CURRENT PASSWORD;

Carol can now authenticate with either password. Once all clients have moved to the new one, retire the old password with:

ALTER READYSET MODIFY USER 'carol' DISCARD OLD PASSWORD;

A later MODIFY USER ... RETAIN CURRENT PASSWORD replaces any old retained password with the current password, so only two passwords are ever valid at a time. MODIFY USER without the clause changes the current password only and leaves a retained one alone. DISCARD OLD PASSWORD is accepted even if there is no old password.

To start a deployment already mid-rotation, name the user twice in --allowed-users. The first password is the current one and the second is the retained one:

readyset --allowed-users 'carol:newpassword,carol:oldpassword'

Password rotation is available with a MySQL upstream only, mirroring MySQL's own dual-password support. Both clauses, and a repeated user in --allowed-users, are rejected in PostgreSQL mode.

Rotate the upstream account first, using MySQL's own ALTER USER ... RETAIN CURRENT PASSWORD, and only then run the Readyset statement. Readyset connects to your database with whichever of the two passwords the client presented, and checks cache authorization with the current one, so both passwords must already be valid upstream. When the rotation is complete, discard the old password in Readyset before discarding it upstream.

Listing the current users

The readyset.users system view lists the usernames that may authenticate right now, including runtime changes. Passwords are never exposed.

SELECT "user" FROM readyset.users;

user is a reserved word in PostgreSQL, so quote the column there; on MySQL SELECT user FROM readyset.users works unquoted. The has_old_password column reports whether the user has a password rotation in progress.

How it fits with the rest of Readyset

Authentication verifies each connection against this set, whichever method the client protocol negotiates. On MySQL, caching_sha2_password keeps a per-user fast-auth digest; MODIFY USER and DROP USER clear it as part of the change, so a rotated password cannot be bypassed by a client that authenticated earlier. A retained password keeps a digest of its own until it is discarded.

Cache authorization decides which users are served from a cache, by asking your database what each of them is allowed to read. ADD USER and MODIFY USER schedule that check for the new user, so they start getting cache hits as soon as their privileges are confirmed; DROP USER forgets them. Until then their queries are simply proxied to your database.