How to Reset Keycloak Admin Password and Recover Access

Tested on Red Hat Enterprise Linux 10.2 (Coughlan)
Package quay.io/keycloak/keycloak:26.7.3
Applies to Keycloak 26.x from ZIP or systemd, Docker, Podman, or Kubernetes — recovery uses the same bootstrap-admin command; stopping Keycloak and running it against your database differ by deployment
Privilege Ability to stop every Keycloak node and run bootstrap-admin with the same database configuration as production
Scope Recover lost admin access when master already exists — not first-time bootstrap (see Keycloak bootstrap admin)
Related guides Create and manage Keycloak users
Keycloak environment variables
Install Keycloak with Podman
Short on time?Beta Get the gist of this 9-minute read in seconds, then ask follow-up questions

You already have Keycloak installed, but you can no longer sign in to the Admin Console — wrong password, locked account, or interactive login (OTP/WebAuthn) blocking access.

This guide walks through admin recovery: create a temporary administrator with Keycloak’s offline bootstrap-admin command, reset your permanent admin, then remove the temporary account. It assumes the master realm already exists.

Quick answer: If another administrator can still sign in, open Users → select the affected admin → Credentials → Reset password. You do not need bootstrap-admin. Use bootstrap-admin only when no administrator can sign in.

IMPORTANT
Installing Keycloak for the first time? You do not need recovery — set bootstrap credentials before the first start instead. See Keycloak bootstrap admin: create the initial admin user.

Choose your Keycloak admin recovery path

Situation What to do
Forgot admin password (no other admin can sign in) Normal recovery with bootstrap-admin user
Another administrator still works Sign in as that admin → Users → Credentials → reset password — no bootstrap-admin needed
OTP or WebAuthn blocks login Service-account recovery with bootstrap-admin service
Changed KC_BOOTSTRAP_ADMIN_PASSWORD but old password still works Bootstrap env vars cannot reset an existing admin — use normal recovery
Recovery user works but production data missing Wrong database — Recovery admin not working? Check the Keycloak database

How Keycloak admin recovery works

bootstrap-admin is a Keycloak mechanism, not a Docker, Podman, Kubernetes, or ZIP feature. Your deployment only changes how you stop Keycloak and how you invoke kc.sh with the correct database settings.

The workflow in order:

  1. Stop every Keycloak node that uses this database before running bootstrap-admin.
  2. Run bootstrap-admin against the same database the server uses.
  3. Keycloak creates a temporary recovery administrator in master.
  4. Start Keycloak again.
  5. Sign in with the temporary account.
  6. Reset the permanent administrator (Admin Console or kcadm.sh).
  7. Delete the temporary user or service client.

The sections below translate these steps for each deployment type.


Step 1 — Stop every Keycloak node

Recovery modifies the Keycloak database. Every Keycloak process that connects to that database must be stopped first.

Deployment Example
systemd (ZIP) sudo systemctl stop keycloak
Docker docker stop keycloak
Podman podman stop keycloak
Kubernetes (Deployment/StatefulSet) kubectl scale deployment keycloak --replicas=0 -n keycloak
Kubernetes (Keycloak Operator) Scale the Operator-managed Keycloak deployment to zero replicas, or follow the Operator recovery notes below

External PostgreSQL does not need a separate “unlock” — only Keycloak nodes must stop. With embedded H2, a running server keeps the database file locked and bootstrap-admin fails with Database may be already in use.


Step 2 — Create a temporary recovery administrator

Use the same database configuration as production (kc.conf, data directory, or KC_DB_*).

Generic Keycloak (ZIP layout):

bash
export RECOVERY_PASS='RecoveryAdm!2026'
bin/kc.sh bootstrap-admin user \
  --username recovery-admin \
  --password:env RECOVERY_PASS \
  --no-prompt

If the server normally runs start --optimized, add --optimized and keep runtime DB options only — see Recovery admin not working? Check the Keycloak database.

Expected output:

output
KC-SERVICES0077: Created temporary admin user with username recovery-admin

If you omit --username, Keycloak defaults to temp-admin.

ZIP or systemd

Run the command on the host with the same kc.conf / env as the server, while the service is stopped.

Docker or Podman

Run a one-off container with the same image tag and the same database configuration as the server. For start-dev with an embedded database, mount the same data volume. For PostgreSQL, pass the same KC_DB_* environment variables — not necessarily the same volume:

bash
docker run --rm \
  -v keycloak-data:/opt/keycloak/data \
  -e RECOVERY_PASS='RecoveryAdm!2026' \
  quay.io/keycloak/keycloak:26.7.3 bootstrap-admin user \
  --username recovery-admin --password:env RECOVERY_PASS --no-prompt

Replace docker with podman where needed.

Kubernetes without Keycloak Operator

For a hand-written Deployment or StatefulSet, the recovery command must run from a Keycloak container that can reach the same production database as the running server. Scale Keycloak to zero replicas first.

Run a one-off Job or debug pod using:

  • the same container image tag as production
  • the same database Secret / KC_DB_* env as the Keycloak Deployment
  • the same PVC only when your deployment stores embedded data on a PVC (uncommon in production; external PostgreSQL is typical)

The bootstrap-admin arguments match the generic example; only the pod wrapper differs. See Install Keycloak on Kubernetes for the Operator-managed StatefulSet layout.

Example Job skeleton:

yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: keycloak-recovery
  namespace: keycloak
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: bootstrap-admin
        image: quay.io/keycloak/keycloak:26.7.3
        envFrom:
        - secretRef:
            name: keycloak-db
        command:
        - /opt/keycloak/bin/kc.sh
        - bootstrap-admin
        - user
        - --username
        - recovery-admin
        - --password:env
        - RECOVERY_PASS
        - --no-prompt
        env:
        - name: RECOVERY_PASS
          value: RecoveryAdm!2026

Apply the Job only after every Keycloak pod is stopped.

Kubernetes with Keycloak Operator

Once master exists, the Operator ignores bootstrap environment variables on the Keycloak CR. Recovery requires running the bootstrap-admin CLI inside a pod that uses the same database configuration as the Operator-managed Keycloak instance.

Typical sequence:

  1. Scale the Operator-managed Keycloak deployment to zero replicas (or stop the Keycloak CR workload per your Operator version docs).
  2. Start a short-lived pod with the same Keycloak image and same database Secret / env as the CR.
  3. Run kc.sh bootstrap-admin user … in that pod.
  4. Scale Keycloak back up and continue with Step 3.

The official Operator documentation describes this CLI-based recovery path when bootstrap configuration no longer applies.


Step 3 — Start Keycloak and sign in

Start the server the way you normally do (systemctl start, docker start, kubectl scale … --replicas=1).

Sign in at /admin/ as recovery-admin. Optionally verify credentials with a token request — the command asks Keycloak for an access token using the recovery username and password:

bash
curl -s -X POST 'http://localhost:8080/realms/master/protocol/openid-connect/token' \
  -d 'client_id=admin-cli' -d 'grant_type=password' \
  -d 'username=recovery-admin' -d 'password=RecoveryAdm!2026' \
  | grep -o '"access_token"'

An access_token line confirms the recovery account works.


Step 4 — Reset your permanent admin password

Creating recovery-admin only restores temporary access. Reset your permanent administrator next.

Admin Console (beginner-friendly)

  1. Sign in to master as the recovery user.
  2. Open Users → select the admin user (or your permanent admin).
  3. Open Credentials → Reset password.
  4. Enter the new password. For a permanent password, set Temporary to Off, then click Set password.

kcadm.sh (CLI alternative)

From the Keycloak install (or kubectl exec / docker exec into the running pod):

bash
bin/kcadm.sh config credentials \
  --server http://localhost:8080 --realm master \
  --user recovery-admin --password 'RecoveryAdm!2026'

Set a new password on the permanent admin user:

bash
bin/kcadm.sh set-password -r master \
  --username admin --new-password 'NewAdminPass!2026'

Confirm the permanent admin can sign in before you delete the recovery account.


Step 5 — Delete the temporary recovery admin

In the Admin Console (signed in as the repaired permanent admin), open Users, delete recovery-admin or temp-admin.

Start any remaining cluster nodes and verify sign-in with the permanent admin. Do not leave a temporary recovery account in production.


Recover an admin locked by OTP or WebAuthn

If the administrator is locked out because interactive authentication requires OTP or WebAuthn — not because the password alone is wrong — a recovery user may not be enough.

A service account authenticates with a client ID and client secret instead of an interactive login. That lets kcadm.sh remove the OTP credential after you bring Keycloak back up.

Sequence:

  1. Stop every Keycloak node.
  2. Run bootstrap-admin service to create a temporary service client.
  3. Start Keycloak again.
  4. Authenticate kcadm.sh with the service client.
  5. Delete the OTP credential from the permanent admin user.
  6. Sign in as admin with password only, then delete the recovery client.

Stop every node, then create the service account:

bash
export SERVICE_SECRET='SvcSecret!2026'
bin/kc.sh bootstrap-admin service \
  --client-id recovery-sa \
  --client-secret:env SERVICE_SECRET \
  --no-prompt

Start Keycloak. Authenticate kcadm.sh:

bash
bin/kcadm.sh config credentials \
  --server http://localhost:8080 --realm master \
  --client recovery-sa --secret 'SvcSecret!2026'

Look up the admin user id:

bash
bin/kcadm.sh get users -r master -q username=admin --fields id,username

List credentials and find the OTP entry:

bash
bin/kcadm.sh get users/USER_ID/credentials -r master

Delete the OTP credential (replace CREDENTIAL_ID with the id whose "type" is otp):

bash
bin/kcadm.sh delete users/USER_ID/credentials/CREDENTIAL_ID -r master

Sign in as admin with password only, then delete the recovery-sa client from Clients in master.

Use the same one-off container / Job pattern as Step 2 when Keycloak runs in Docker, Podman, or Kubernetes.


Recovery admin not working? Check the Keycloak database

If bootstrap-admin points at a different data directory or JDBC URL than production, the recovery account is created in the wrong database. Recovery appears to succeed but your real installation is unchanged.

Server runtime Recovery must match
Embedded dev data (start-dev) Same /opt/keycloak/data volume or directory
PostgreSQL start Same KC_DB, KC_DB_URL, username, and password
Optimized production Same DB settings; add --optimized when the server uses start --optimized

For PostgreSQL, pass the same KC_DB_* values to bootstrap-admin that you pass to start — see Configure Keycloak with PostgreSQL.

If the installation was built with kc.sh build and runs start --optimized, pass --optimized to bootstrap-admin as well. Otherwise Keycloak may run an implicit build before the command completes.


Keycloak admin recovery troubleshooting

Symptom Likely cause Fix
Database may be already in use / H2 file locked A Keycloak node still running (embedded H2) Stop all Keycloak nodes before bootstrap-admin
Recovery login works but real data missing Wrong database path or JDBC URL Re-run against production volume or KC_DB_*
Local access required after adding bootstrap env vars master already exists; vars cannot create admin Use bootstrap-admin user — see Step 2
Changed bootstrap env; password unchanged Bootstrap vars do not reset existing admins Normal recovery workflow — not a bootstrap-env issue
Temporary banner after “fix” Recovery user or client not deleted Remove temporary user/client from master
bootstrap-admin fails on password --no-prompt without --password:env Export password in env and reference it with --password:env VAR
Another admin can still sign in Recovery not required Reset affected user from Users → Credentials — no bootstrap-admin

Summary

When you cannot sign in to the Keycloak Admin Console and no other administrator can help, stop every Keycloak node, run bootstrap-admin user against the same database as production, start the server, sign in as the temporary account, reset the permanent admin (Temporary → Off in the Admin Console for a permanent password), and delete the recovery user.

If another administrator can still sign in, reset the password from Users → Credentials instead. If OTP or WebAuthn blocks interactive login, use bootstrap-admin service and remove the OTP credential with kcadm.sh. For first-time installation, use Keycloak bootstrap admin instead — recovery is not the first-start path.


References

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)