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

# Oracle

> Connect Bytebase to Oracle Database, including RAC, Data Guard, and encrypted TCPS connections with an Oracle wallet.

To add an Oracle database, go to **Instances**, click **Connect instance**, and choose **Oracle**.

## Supported versions

Bytebase supports Oracle Database 11g and later. It connects through a built-in driver, so there is no Oracle Client, Instant Client, or JDBC driver to install.

## Create a user for Bytebase

Create the user in the database Bytebase connects to, which is the pluggable database you enter as **Service name**. Grant it broad privileges so that Bytebase can manage the schemas there. The examples name the user `bytebase`.

```sql theme={null}
CREATE USER bytebase IDENTIFIED BY "<password>";
GRANT ALL PRIVILEGES TO bytebase;
```

Put the password in double quotes. Single quotes fail with `ORA-00988: missing or invalid passwords`.

On Amazon RDS for Oracle, the master user can't grant `ALL PRIVILEGES`, because RDS withholds `GRANT ANY PRIVILEGE` from it. Grant the `DBA` role instead:

```sql theme={null}
GRANT DBA TO bytebase;
```

## Connection details

### Hostname

The host name or IP address of the Oracle listener, such as `db.example.com`. For a RAC cluster, enter the SCAN name, as described in [Connect to RAC and Data Guard](#connect-to-rac-and-data-guard). For a TCPS connection, it must also be one of the names in the server's certificate, as described in [Step 1](#step-1-copy-the-connection-values-from-tnsnames-ora).

### Port

The listener port. Oracle's default is `1521`. A TCPS listener has its own port, often `2484`.

### Username

The Oracle account Bytebase connects as. Leave it empty only for [certificate login](#step-4-choose-how-bytebase-signs-in).

### Password

The account's password. You can also read it from a [secret manager](https://docs.bytebase.com/get-started/connect/overview.md#secret-manager-integration). With a wallet that stores the password, you can leave this field empty.

### Connect using

Choose how the listener identifies the database:

* **Service name**: the database service, such as a pluggable database (`FREEPDB1`) or a service your DBA created (`sales.example.com`). Use a service name to reach a pluggable database.
* **SID**: the instance's system identifier, such as `ORCL`.

Bytebase lists the user-owned schemas in that database as Bytebase databases. See [Database](https://docs.bytebase.com/concepts/database.md).

### TLS

Bytebase does not use the **TLS** settings for Oracle, so leave **TLS mode** at **Disabled**. To encrypt the connection, use an Oracle wallet as described in [Connect over TCPS with an Oracle wallet](#connect-over-tcps-with-an-oracle-wallet).

### Extra Parameters

Options that Bytebase passes to its built-in driver, [go-ora](https://github.com/sijms/go-ora), as key-value pairs. Click **Add parameter** to add one. Keys aren't case-sensitive, except for `CONNECTION TIMEOUT`. The wallet keys are listed in [Step 3](#step-3-add-the-extra-parameters). The keys for a second address and a connection timeout are listed in [Data Guard](#data-guard).

## Connect over TCPS with an Oracle wallet

> [!NOTE]
>
> Requires self-hosted Bytebase 3.5.1 or later. Bytebase reads the wallet from its own file system, which Bytebase Cloud doesn't provide.

TCPS is Oracle Net over TLS. Your DBA enables it by adding a TCPS endpoint to the listener, backed by a server wallet that holds the server's certificate and private key. Bytebase connects with a client wallet of its own.

### How wallets work

An Oracle wallet is a directory of certificate files. The client wallet you give Bytebase can hold three kinds of entries:

* **Trusted certificates**: the server's certificate, or the certificate authority (CA) that signed it. Every wallet needs one so that Bytebase can verify the server. A wallet with only trusted certificates gives you one-way TLS.
* **A client certificate and its private key**: needed when the listener requires client certificates, which is called mutual TLS (mTLS). Bytebase presents the certificate automatically. Autonomous Database wallets include one.
* **Stored passwords**: database logins saved with `mkstore`, which Bytebase can use instead of the **Password** field.

Bytebase opens `cwallet.sso`, the auto-login file, or `ewallet.p12` when you give it the wallet password. It doesn't read `tnsnames.ora`, `sqlnet.ora`, the `TNS_ADMIN` environment variable, or the `.jks` and `.pem` files that some wallets include.

![A tnsnames.ora entry supplies Hostname, Port and Service name, which you copy into the Bytebase form. Bytebase opens cwallet.sso from the wallet directory and ignores the other files.](https://mintcdn.com/dbx/lmCMH9K79KTJ2GDq/content/docs/concepts/oracle-wallet-connection-d25f414f.svg?fit=max\&auto=format\&n=lmCMH9K79KTJ2GDq\&q=85\&s=e01f229ef241a4a04693d4cfb9742ce1)

### Step 1: Copy the connection values from tnsnames.ora

Bytebase doesn't read `tnsnames.ora`, so copy the values from your entry into the form. For example:

```text theme={null}
SALES_TCPS =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCPS)(HOST = db.example.com)(PORT = 2484))
    (CONNECT_DATA = (SERVICE_NAME = sales.example.com))
  )
```

| In `tnsnames.ora` | In Bytebase |
| - | - |
| `HOST` | **Hostname** |
| `PORT` | **Port** |
| `SERVICE_NAME` | **Connect using** > **Service name** |
| `SID` | **Connect using** > **SID** |

Bytebase checks **Hostname** against the Subject Alternative Names (SANs) in the server's certificate and ignores the certificate's Common Name. Use a host name listed there, or an IP address listed as an IP entry. If Bytebase reaches the database through another name, such as a load balancer or `host.docker.internal`, ask your DBA to add that name to the certificate.

### Step 2: Make the wallet readable by Bytebase

The wallet must be a directory on the machine or container that runs Bytebase, readable by the user that runs it.

**On a host.** Copy the wallet to a local directory and use that directory's path.

**In Docker.** Mount the wallet directory read-only by adding one `--volume` line to the [Docker command](https://docs.bytebase.com/get-started/self-host/deploy-with-docker.md). The wallet path is then `/etc/oracle-wallet`.

```bash theme={null}
docker run --rm --init \
  --name bytebase \
  --publish 8080:8080 --pull always \
  --volume ~/.bytebase/data:/var/opt/bytebase \
  --volume <wallet_directory>:/etc/oracle-wallet:ro \
  bytebase/bytebase:latest
```

If you can't change how the container starts, copy the wallet into the data directory you already mount, such as `~/.bytebase/data/oracle-wallet`, and use `/var/opt/bytebase/oracle-wallet`. This works only when the data directory is a directory on the host, not a named Docker volume.

**On Kubernetes.** Mount the wallet into the Bytebase pod, for example from a Secret, and use the mount path.

The Bytebase container runs as root by default. If you run it as the image's `bytebase` user (`--user bytebase`, uid `113`), make the wallet readable by that user, for example with `chmod -R a+rX <wallet_directory>`.

### Step 3: Add the extra parameters

In **Extra Parameters**, click **Add parameter** for each key:

| Key | Value | When to set it |
| - | - | - |
| `SSL` | `TRUE` | Always. Without it, Bytebase connects without TLS, even when `WALLET` is set. |
| `WALLET` | The wallet directory, such as `/etc/oracle-wallet` | Always. Bytebase opens `cwallet.sso` in it. |
| `WALLET PASSWORD` | The wallet password | Only when the directory has `ewallet.p12` but no `cwallet.sso`. Bytebase then opens `ewallet.p12`. |
| `SSL VERIFY` | `FALSE` | Only to diagnose a certificate error. It turns off the certificate and hostname checks, so remove it afterward. |

Leave the **TLS** section at **Disabled**.

### Step 4: Choose how Bytebase signs in

**Password.** Fill in **Username** and **Password**. Bytebase always uses a filled-in password, even when the wallet stores a different one.

**Password stored in the wallet.** Fill in **Username** and leave **Password** empty. Bytebase uses the wallet entry for that user whose connect descriptor has the same host, port, and service name as the form. Entries can't match a connection that uses a SID. To add an entry, run the following command; `mkstore` prompts for the wallet password:

```bash theme={null}
mkstore -wrl <wallet_directory> -createCredential "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=<host>)(PORT=<port>))(CONNECT_DATA=(SERVICE_NAME=<service_name>)))" <user> <password>
```

**Certificate.** Add `AUTH TYPE` with the value `TCPS` to **Extra Parameters**, and leave **Username** and **Password** empty. Oracle signs Bytebase in as the database user identified by the wallet's client certificate. This needs:

* A wallet with a client certificate, and a listener that requires client certificates.
* A database user created with `IDENTIFIED EXTERNALLY AS '<certificate_dn>'`, such as `'CN=bytebase'`.
* `TCPS` in `SQLNET.AUTHENTICATION_SERVICES` in the server's `sqlnet.ora`.

### Step 5: Test the connection

Click **Test Connection**, then **Create**. To confirm that the session is encrypted, open one of the instance's databases in **SQL Editor** and run:

```sql theme={null}
SELECT SYS_CONTEXT('USERENV', 'NETWORK_PROTOCOL') AS protocol FROM dual;
```

The result is `tcps`.

### Autonomous Database

By default, Autonomous Database accepts only mutual TLS connections, so Bytebase connects with the database's wallet. To connect, follow these steps:

1. Download the wallet as described in [Oracle's instructions](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/connect-download-wallet.html), and unzip it. Bytebase opens the auto-login `cwallet.sso`, so it doesn't need the password you set during the download.
2. Make the unzipped directory readable by Bytebase, as described in [Step 2](#step-2-make-the-wallet-readable-by-bytebase).
3. Copy the host, port, and service name from the wallet's `tnsnames.ora` entry you want to use, such as `<database_name>_low`. The host is the regional endpoint, such as `adb.us-ashburn-1.oraclecloud.com`, and the port is usually `1522`. The regional endpoint is one of the names in the database's certificate, so leave `SSL VERIFY` unset.
4. In **Extra Parameters**, set `SSL` to `TRUE` and `WALLET` to the wallet directory.
5. Sign in as `ADMIN` or another database user, with its password.

### Troubleshooting

**Test Connection** shows the error from the driver:

| Error | Cause | Fix |
| - | - | - |
| `connection reset by peer` or `EOF` | Bytebase and the listener disagree about TLS. Usually `SSL` is missing for a TCPS port, because `WALLET` alone doesn't turn on TLS. It also happens when `SSL` is set for a port without TLS. | Add `SSL` with the value `TRUE`, and check that **Port** is the TCPS port. |
| `open …/cwallet.sso: no such file or directory` | There is no `cwallet.sso` at the `WALLET` path as Bytebase sees it, or the wallet has only `ewallet.p12`. | Check the path inside the Bytebase container. For a wallet with only `ewallet.p12`, add `WALLET PASSWORD`. |
| `open …/cwallet.sso/cwallet.sso: not a directory` | `WALLET` points at the `cwallet.sso` file instead of its directory. | Set `WALLET` to the directory. |
| `open …/cwallet.sso: permission denied` | The user that runs Bytebase can't read the wallet. | Make the files readable, for example with `chmod -R a+rX <wallet_directory>`. |
| `x509: certificate signed by unknown authority` | TLS is on, but Bytebase didn't load a wallet, or the wallet doesn't trust the server's certificate. | Set `WALLET`, and make sure the wallet holds the server's certificate or its CA. |
| `x509: certificate is valid for …, not …` | **Hostname** isn't among the SANs in the server's certificate. | Use a name from the certificate, or have the certificate reissued. To confirm the cause, add `SSL VERIFY` with the value `FALSE`, then remove it. |
| `x509: certificate relies on legacy Common Name field, use SANs instead` | The server's certificate has no SANs, and Bytebase doesn't use the Common Name. The Autonomous Database Free container image issues a certificate like this. | Have the certificate reissued with SANs. For a local test database only, add `SSL VERIFY` with the value `FALSE`. |
| `remote error: tls: certificate required` | The listener requires a client certificate, and the wallet has none that the server trusts. | Use a wallet with a client certificate whose CA the server trusts. |
| `cannot find credentials for server: …` | **Password** is empty, and the wallet has no stored password for this user, host, port, and service name. | Fill in **Password**, or add a matching wallet entry. |
| `ORA-01017: invalid credential or not authorized; logon denied` | The password is wrong. With a wallet, **Username** may be empty without `AUTH TYPE`, or filled in with `AUTH TYPE`. | Check the password. For certificate login, leave **Username** and **Password** empty. |
| `invalid Wallet header version` or `can't read Wallet with auto login local properties` | The wallet was created with `orapki ... -auto_login_local`, which locks it to the machine that created it. | Create the wallet with `-auto_login` instead. |

## Connect to RAC and Data Guard

Oracle Real Application Clusters (RAC) runs one database on several servers. Oracle Data Guard keeps a standby copy of the database, usually at another site, and can move the primary role to it. To keep Bytebase connected when the database moves to another server or site, enter a cluster or site address and a service name instead of a single server and a SID:

| Setup | Hostname | Connect using | Extra Parameters |
| - | - | - | - |
| RAC | The cluster's SCAN name | **Service name** | None |
| Data Guard | The primary site's address | **Service name**, with a service that runs only on the primary | `SERVER` with the standby site's address |
| RAC with Data Guard | The primary site's SCAN name | **Service name**, with a service that runs only on the primary | `SERVER` with the standby site's SCAN name |

Add each database to Bytebase as one instance. Don't add an instance for each RAC node. Don't add a Data Guard standby as another instance to deploy changes to, because Data Guard copies every change from the primary.

### RAC

To connect to a RAC database, follow these steps:

1. In **Hostname**, enter the cluster's Single Client Access Name (SCAN), such as `sales-scan.example.com`.
2. In **Port**, enter the SCAN listener port. Oracle's default is `1521`.
3. In **Connect using**, choose **Service name** and enter a service that your DBA created for the cluster, such as `sales_rw`.

Don't choose **SID**. A SID names one instance on one node, so the connection can't move to another node.

A SCAN listener picks an instance and redirects Bytebase to the listener on that instance's node. Bytebase then connects to the node itself, usually at its virtual IP (VIP) address. Make sure that Bytebase can resolve and reach every node's address on the listener port, not only the SCAN addresses.

When a node fails, the sessions on that node end. The next time Bytebase connects, the SCAN listener sends it to a node that is still running.

If the cluster has no SCAN, enter one node's address in **Hostname** and list the other nodes in `SERVER`, as described in [Data Guard](#data-guard).

### Data Guard

> [!NOTE]
>
> Requires Bytebase 3.5.1 or later.

After a switchover or failover, the primary database runs at the other site. For Bytebase to follow it, the instance needs the addresses of both sites and a service that only the primary offers.

To connect to a Data Guard configuration, follow these steps:

1. Ask your DBA for a service that Oracle starts only on the database in the primary role, such as `sales_rw`. Oracle's documentation describes this as setting the [database role for a service](https://docs.oracle.com/en/database/oracle/oracle-database/19/racad/workload-management-with-dynamic-database-services.html). Don't use the default service named after the pluggable database. Every database in the configuration can offer it, so it doesn't lead Bytebase to the primary.

2. In **Hostname** and **Port**, enter the primary site's listener address. For a RAC primary, enter its SCAN name.

3. In **Connect using**, choose **Service name** and enter that service.

4. In **Extra Parameters**, add the following keys:

   | Key | Value | What it does |
   | - | - | - |
   | `SERVER` | The standby site's address and port, such as `scan-b.example.com:1521` | Gives Bytebase a second address to try. The port is required. For more than one standby, separate the addresses with commas. |
   | `CONNECTION TIMEOUT` | A number of seconds, such as `5` | Limits how long Bytebase waits for an address to accept a connection. Without it, Bytebase waits about two minutes for a site that doesn't respond before it tries the next address. It doesn't limit how long a statement runs. |

5. Click **Test Connection**.

Enter `CONNECTION TIMEOUT` in uppercase, exactly as shown. Bytebase sets this key itself, and a key spelled differently doesn't reliably replace its value.

Each time Bytebase connects, it tries the **Hostname** address first and then each `SERVER` address in order. It moves to the next address when an address refuses the connection, can't be reached, or has a listener that doesn't offer the service. After a role change, the former primary stops offering the service, so Bytebase reaches the new primary without any change to the instance.

![The same Bytebase instance before and after a role change. Hostname is the address of site A, the service name is sales\_rw, and the SERVER extra parameter is the address of site B. In normal operation, site A is the primary and answers at the first address. After a switchover or failover, site A no longer offers the service, so Bytebase connects to site B, the new primary, at the second address.](https://mintcdn.com/dbx/1qH75NLyPGaj8DXj/content/docs/concepts/oracle-data-guard-connection-6e5fb65c.svg?fit=max\&auto=format\&n=1qH75NLyPGaj8DXj\&q=85\&s=b6fa27997349a557a0d56f47364b41bd)

A change that is running when the roles change fails with a connection error, and Bytebase doesn't resume it. Oracle commits each DDL statement as it runs, so check which statements were applied before you run the task again.

### Other configurations

* **Cold failover cluster.** With RAC One Node, Standard Edition High Availability, or a third-party cluster, one instance runs at a time and its address moves with it. Enter that address and a service name. You don't need extra parameters.
* **Amazon RDS Multi-AZ.** Enter the DB instance endpoint. Amazon RDS points the endpoint at the standby during a failover.
* **Two writable sites with Oracle GoldenGate.** Add each site as its own instance. A schema change reaches the other site only if GoldenGate replicates DDL between them. Otherwise, deploy the change to both instances.

### Troubleshoot RAC and Data Guard connections

**Test Connection** shows the error from the driver. When Bytebase tries several addresses, it shows the error from the last one.

| Error | Cause | Fix |
| - | - | - |
| `ORA-12514: TNS:listener does not currently know of service requested in connect descriptor` | None of the addresses offers the service. The service name is wrong, or the service isn't running, which can happen in the middle of a role change. | Check the service name, and ask your DBA whether the service is running on the primary. |
| `address <host>: missing port in address` | A `SERVER` value has no port. | Write each address as `<host>:<port>`. |
| `dial tcp <address>: connect: no route to host` or `dial tcp <address>: i/o timeout`, where the address isn't one you entered | A SCAN listener redirected Bytebase to a node address that Bytebase can't reach. | Allow Bytebase to reach every node's listener address. If you don't recognize the address, ask your DBA which addresses the nodes register with the SCAN listener. |
| `dial tcp <address>: connect: connection refused` | Nothing listens at that address and port. | Check the port in **Port** and in each `SERVER` value. |
| `EOF` | An address accepted the connection and then closed it without answering as an Oracle listener. A TCP proxy or load balancer in front of a site that is down can do this. Bytebase stops at that address and doesn't try the next one. | Point **Hostname** and `SERVER` at the listeners themselves, or set the proxy to refuse connections when its site is down. If the listener uses TCPS, see the [wallet troubleshooting](#troubleshooting). |
| **Test Connection** succeeds, but only after about two minutes | The first address doesn't respond, and Bytebase waits for it before it tries the next one. | Add `CONNECTION TIMEOUT`, as described in [Data Guard](#data-guard). |
| `ORA-16000` when a change runs | Bytebase is connected to a standby, which is open only for queries. | Use a service that runs only on the primary. |

## Read-only connection

A [read-only connection](https://docs.bytebase.com/get-started/connect/overview.md#read-only-connections) has its own **Extra Parameters**. To use one with a TCPS listener, add the same `SSL` and `WALLET` entries to it.

With Oracle Active Data Guard, a standby stays open for queries while it applies changes from the primary. To run SQL Editor queries on the standby, enter the standby site's address in the read-only connection, with a service that runs only on a standby, such as `sales_ro`. Add the primary site's address in `SERVER`, so that the connection still finds the standby after a role change. Bytebase can sync and query a database that is open only for queries.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.