> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bytebase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Recover Administrator Access

<Info>
  Available only for:

  * Self-hosted Bytebase version 3.22.0 and later
  * Shell access to the host, or `kubectl` access to the cluster, that runs Bytebase
</Info>

When nobody can sign in, `bytebase recovery` restores password sign-in from the command line. It opens an interactive menu with two actions, **Enable password sign-in** and **Reset user password**, and changes the metadata database directly, so it works while the console is unreachable.

Recovery requires downtime. If any **Workspace Admin** can still sign in, reset passwords, roles, and 2FA from the console instead.

## Recovery actions and limits

| Situation                                                                                                                             | Recovery action                                                                                    |
| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| An administrator knows their password, but **Disallow signin with email & password** is on                                            | **Enable password sign-in**                                                                        |
| A user's password is unknown, or the user is locked out after too many failed password attempts                                       | **Reset user password**                                                                            |
| **Disallow signin with email & password** is on and no administrator knows a password, for example because all administrators use SSO | **Reset user password** for an administrator, then **Enable password sign-in** in the same session |
| A user was removed from **Members** and has no workspace role                                                                         | **Reset user password**, then confirm adding the user and select a role                            |

Recovery can't do the following:

* **Create or reactivate a user**: the target must be an existing, active user. Service accounts and workload identities are rejected.
* **Change the role of a user who already has one**: the command offers a role only when the user has no workspace role, whether direct, through a group, or through `allUsers`. If no active **Workspace Admin** is left and every user already has a role, recovery can't restore administrator access.
* **Reset two-factor authentication**: only another **Workspace Admin** can [reset a user's 2FA](/administration/2fa#reset-a-users-two-factor-authentication).
* **Bypass the workspace domain**: when **Members restriction** is on, the user's email must belong to an allowed [workspace domain](/administration/sign-in-restriction#sign-in-from-email-domains).

If none of the actions fits, [contact us](https://www.bytebase.com/contact-us/).

## Run recovery

<Warning>
  Stop every Bytebase server that uses the metadata database before you run recovery, and keep them stopped until the session exits. Running servers cache the settings, users, and roles that recovery changes.
</Warning>

Run `bytebase recovery` from an interactive terminal, with the same Bytebase version and the same metadata configuration as the stopped server. Recovery doesn't migrate the metadata schema, so the version must match exactly: never use a floating image tag such as `latest`.

<Tabs>
  <Tab title="Docker">
    The commands assume the container is named `bytebase`. Substitute your own container name. Because the server container is stopped, recovery runs in a one-off container. Keep `-it`, because recovery only accepts input from a terminal.

    1. Check the version and the image before you stop the server:

       ```bash theme={null}
       docker inspect --format '{{index .Config.Labels "org.opencontainers.image.version"}} {{.Image}}' bytebase
       ```

       If the version is older than 3.22.0, stop here and [upgrade](/get-started/self-host/upgrade) first. Use the printed image ID as `<image>` in the next steps, so recovery and the restart run the exact image the server ran.

    2. Stop Bytebase:

       ```bash theme={null}
       docker stop bytebase
       ```

    3. Back up the metadata: the [data directory](/get-started/self-host/upgrade#back-up-the-data-directory) for embedded PostgreSQL, or the [metadata database](/get-started/self-host/upgrade#back-up-the-metadata-database) for external PostgreSQL.

    4. Run recovery with the same flags the server uses to reach its metadata. For embedded PostgreSQL, that is the data volume:

       ```bash theme={null}
       docker run --rm -it --name bytebase-recovery \
         --volume <host_data_dir>:/var/opt/bytebase \
         <image> recovery
       ```

       If the server passes `--data`, mount that path instead and pass the same `--data` after `recovery`.

       For external PostgreSQL, that is `PG_URL`:

       ```bash theme={null}
       docker run --rm -it --name bytebase-recovery \
         -e 'PG_URL=<pg_url>' \
         <image> recovery
       ```

       Add every other flag the server needs to reach PostgreSQL: `--network` or `--add-host`, the `--volume` of a connection-string file or TLS certificate, and the credential variables for IAM authentication. If `PG_URL` is a file path, mount that file.

    5. After you exit the session, start Bytebase again on the same image. If your `docker run` command uses a floating tag or `--pull always`, replace the image name with `<image>` and drop `--pull always`, so the restart doesn't upgrade Bytebase.
  </Tab>

  <Tab title="Kubernetes">
    The commands work for both the Helm chart and the manifest from [Deploy with Kubernetes](/get-started/self-host/deploy-with-kubernetes). Both create a StatefulSet named `bytebase`, with Pods labeled `app=bytebase`, that uses external PostgreSQL. Because the server Pods are stopped, recovery runs in a one-off Pod. Keep `-it`, because recovery only accepts input from a terminal.

    1. Check the version before you scale down:

       ```bash theme={null}
       kubectl -n <namespace> exec bytebase-0 -- bytebase version
       ```

       If the version is older than 3.22.0, stop here and [upgrade](/get-started/self-host/upgrade) first. If the image tag is floating, such as `latest`, use the printed version as the tag in step 4.

    2. Stop every replica, then repeat the second command until it lists no Pods:

       ```bash theme={null}
       kubectl -n <namespace> scale statefulset bytebase --replicas=0
       kubectl -n <namespace> get pods -l app=bytebase
       ```

       Pause `helm upgrade` and any GitOps sync, such as Argo CD or Flux, until recovery finishes, because they restore the replica count.

    3. [Back up the metadata database](/get-started/self-host/upgrade#back-up-the-metadata-database), or take a snapshot with your managed PostgreSQL service.

    4. Run recovery in a one-off Pod with the same image and `PG_URL` as the server. If the StatefulSet sets `PG_URL` as a literal `value`, pass the same value:

       ```bash theme={null}
       kubectl -n <namespace> run bytebase-recovery \
         --rm -it --restart=Never \
         --image=<image> \
         --env='PG_URL=<pg_url>' \
         --command -- bytebase recovery
       ```

       If the menu doesn't appear, press Enter.

           <Accordion title="PG_URL uses valueFrom, a file path, or IAM authentication">
             Create a Pod that gets `PG_URL` the same way the server does: give it the same `env` as the Pod template of the StatefulSet, plus any `volumes`, `volumeMounts`, and `serviceAccountName` the template sets. The example reads `PG_URL` from a Secret:

             ```yaml theme={null}
             apiVersion: v1
             kind: Pod
             metadata:
               name: bytebase-recovery
               namespace: <namespace>
             spec:
               restartPolicy: Never
               containers:
                 - name: recovery
                   image: <image>
                   command: ["sleep", "3600"]
                   env:
                     - name: PG_URL
                       valueFrom:
                         secretKeyRef:
                           name: <secret_name>
                           key: <secret_key>
             ```

             If the experimental `escapePassword` option of the chart is on, set `PG_URL` to the full connection string with the password percent-encoded instead.

             Save the manifest as `bytebase-recovery.yaml`, then start the Pod, run recovery inside it, and delete it afterward:

             ```bash theme={null}
             kubectl apply -f bytebase-recovery.yaml
             kubectl -n <namespace> wait --for=condition=Ready pod/bytebase-recovery --timeout=120s
             kubectl -n <namespace> exec -it bytebase-recovery -- bytebase recovery
             kubectl -n <namespace> delete pod bytebase-recovery
             ```
           </Accordion>

    5. After you exit the session, restore the replica count:

       ```bash theme={null}
       kubectl -n <namespace> scale statefulset bytebase --replicas=<replicas>
       ```

       If the image tag is floating, the new Pods pull the newest image, which upgrades Bytebase. Pin the tag to the recorded version first to avoid that.
  </Tab>

  <Tab title="Binary">
    For a `bytebase` binary that runs directly on a host, without a container.

    1. Check the version before you stop the server:

       ```bash theme={null}
       bytebase version
       ```

       If the version is older than 3.22.0, stop here and [upgrade](/get-started/self-host/upgrade) first.

    2. Stop the Bytebase server.

    3. Back up the metadata: the [data directory](/get-started/self-host/upgrade#back-up-the-data-directory) for embedded PostgreSQL, or the [metadata database](/get-started/self-host/upgrade#back-up-the-metadata-database) for external PostgreSQL.

    4. Run recovery with the same binary, as the same OS user that runs the server. For embedded PostgreSQL, pass the same `--data` as an absolute path, and the same `--port` if the server sets one:

       ```bash theme={null}
       bytebase recovery --data <data_dir>
       ```

       For external PostgreSQL, pass the same `PG_URL`:

       ```bash theme={null}
       PG_URL='<pg_url>' bytebase recovery
       ```

    5. After you exit the session, start the Bytebase server again.
  </Tab>
</Tabs>

## Use the recovery session

The session shows a menu until you enter `q`, so you can run several actions in a row. The example resets a password:

```text theme={null}
Select a recovery action:
1. Enable password sign-in
2. Reset user password
q. Exit
> 2
User email (blank to cancel): admin@example.com
Password requirements:
- Minimum length: 8 characters
New password:
Confirm new password:
Resetting user password...
Password updated for user admin@example.com.
```

Each action applies immediately and changes only what it names: the sign-in setting, one user's password, or one role. Exiting at the menu leaves nothing half-done.

* **Enable password sign-in**: switches off **Disallow signin with email & password**. The menu lists it first, but when no administrator knows a password, reset one first.
* **Reset user password**: enforces the workspace [password restriction](/administration/password) and clears the lockout from failed password attempts. It doesn't change the user's 2FA or SSO sign-in.

## After recovery

1. Open Bytebase and sign in with the email and password, then verify the account's access.
2. Repair and test the identity provider.
3. Switch **Disallow signin with email & password** back on in **Settings** > **General** > **Account** if it was on before the outage.
4. Review the recovery events in the [audit log](/security/audit-log). Each action records a warning-level event whose method starts with `/bytebase.cli.Recovery/`.

## Troubleshooting

### Terminal required

```text theme={null}
Error: recovery requires terminal input and output
```

Password entry must stay hidden, so recovery refuses piped or scripted input. In a container, add `-it` to `docker run`, `kubectl run`, or `kubectl exec`. On a host, run the command from an interactive shell, with `ssh -t` when you connect over SSH.

### Data directory not accessible

```text theme={null}
Error: failed to open recovery metadata store: unable to access --data directory /srv/bytebase: stat /srv/bytebase: no such file or directory
```

The `--data` path doesn't exist where recovery runs. With a binary, pass the same `--data` as the server, as an absolute path. With Docker, mount the data volume at that path.

### Embedded metadata database not initialized

```text theme={null}
Error: failed to open recovery metadata store: embedded metadata database is not initialized at "/var/opt/bytebase/pgdata"
```

This error appears only when `PG_URL` isn't set. The data directory exists, but it isn't the one the server uses. With Docker, the volume isn't mounted or the host path is wrong. With a binary, `--data` is missing or wrong. If the server uses external PostgreSQL, pass `PG_URL` instead.

### Embedded metadata database not readable

```text theme={null}
Error: failed to open recovery metadata store: failed to inspect embedded metadata database: stat /srv/bytebase/pgdata/PG_VERSION: permission denied
```

Recovery runs as a different OS user than the server. Run it as the user that owns the data directory.

### External metadata database not connected

```text theme={null}
Error: failed to open recovery metadata store: failed to connect to external metadata database: ...
```

This error appears only when `PG_URL` is set, and the text after the last colon names the cause. Recovery needs everything the server uses to reach PostgreSQL: the network (`--network` or `--add-host` with Docker), a mounted connection-string file when the cause is `failed to read database URL from file`, TLS files, or IAM credentials.

### Unknown command

```text theme={null}
Error: unknown command "recovery" for "bytebase"
```

The image or binary is older than 3.22.0. [Upgrade](/get-started/self-host/upgrade) to 3.22.0 or later, start the server once so it migrates the metadata, then run recovery with the new version.

### No usable workspace administrator

```text theme={null}
Failed to enable password sign-in: no usable workspace administrator has an active end-user identity with a password credential
```

**Enable password sign-in** requires an active **Workspace Admin** user with a password, so that someone can sign in afterward. Run **Reset user password** for an administrator, then retry. If no active administrator is left, reset a user who has no workspace role and add that user as **Workspace Admin**. If every user already has a role, recovery can't restore administrator access.
