
:guide-id: db
:guide-title: Configuring the database
:guide-summary: Configure a relational database for {project_name} to store user, client, and realm data.
:guide-priority: 999
:guide-tile-visible: true
:version: 26.3.3

include::../attributes.adoc[]

[[db]]
= Configuring the database

ifeval::["" == "true"]
WARNING: This {section} is describing a feature which is currently in preview.
ifeval::["" == ""]
Please provide your feedback while we’re continuing to work on this.
endif::[]
ifeval::["" != ""]
Please provide your feedback by link:[joining this discussion] while we’re continuing to work on this.
endif::[]
endif::[]


This {section} explains how to configure the {project_name} server to store data in a relational database.

== Supported databases

The server has built-in support for different databases. You can query the available databases by viewing the expected values for the `db` configuration option. The following table lists the supported databases and their tested versions.

[%autowidth]
|===
|Database | Option value | Tested Version

|MariaDB Server | `mariadb` | 11.4
|Microsoft SQL Server | `mssql` | 2022
|MySQL | `mysql` | 8.4
|Oracle Database | `oracle` | 23.5
|PostgreSQL | `postgres` | 17
|Amazon Aurora PostgreSQL | `postgres` | 16.8
|===

By default, the server uses the `dev-file` database. This is the default database that the server will use to persist data and
only exists for development use-cases. The `dev-file` database is not suitable for production use-cases, and must be replaced before deploying to production.

== Installing a database driver

Database drivers are shipped as part of {project_name} except for the
ifeval::[{project_product} == true]
Oracle Database and Microsoft SQL Server drivers.
endif::[]
ifeval::[{project_product} != true]
Oracle Database driver.
endif::[]

Install the necessary missing driver manually if you want to connect to
ifeval::[{project_product} == true]
one of these databases
endif::[]
ifeval::[{project_product} != true]
this database
endif::[]
or skip this section if you want to connect to a different database for which the database driver is already included.

=== Installing the Oracle Database driver

To install the Oracle Database driver for {project_name}:

. Download the `ojdbc17` and `orai18n` JAR files from one of the following sources:

.. *Zipped JDBC driver and Companion Jars* version 23.6.0.24.10 from the https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html[Oracle driver download page].

.. Maven Central via `link:++https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc17/23.6.0.24.10/ojdbc17-23.6.0.24.10.jar++[ojdbc17]` and `link:++https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/23.6.0.24.10/orai18n-23.6.0.24.10.jar++[orai18n]`.

.. Installation media recommended by the database vendor for the specific database in use.

. When running the unzipped distribution: Place the `ojdbc17` and `orai18n` JAR files in {project_name}'s `providers` folder

. When running containers: Build a custom {project_name} image and add the JARs in the `providers` folder. When building a custom image for the Operator, those images need to be optimized images with all build-time options of {project_name} set.
+
A minimal Containerfile to build an image which can be used with the {project_name} Operator and includes Oracle Database JDBC drivers downloaded from Maven Central looks like the following:
+
[source,dockerfile,subs="attributes+"]
----
FROM quay.io/keycloak/keycloak:{containerlabel}
ADD --chown=keycloak:keycloak --chmod=644 https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc17/23.6.0.24.10/ojdbc17-23.6.0.24.10.jar /opt/keycloak/providers/ojdbc17.jar
ADD --chown=keycloak:keycloak --chmod=644 https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/23.6.0.24.10/orai18n-23.6.0.24.10.jar /opt/keycloak/providers/orai18n.jar
# Setting the build parameter for the database:
ENV KC_DB=oracle
# Add all other build parameters needed, for example enable health and metrics:
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
# To be able to use the image with the {project_name} Operator, it needs to be optimized, which requires {project_name}'s build step:
RUN /opt/keycloak/bin/kc.sh build
----
+
See the link:{links_server_containers_url}[{links_server_containers_name}] {section} for details on how to build optimized images.

Then continue configuring the database as described in the next section.

ifeval::[{project_product} == true]

=== Installing the Microsoft SQL Server driver

To install the Microsoft SQL Server driver for {project_name}:

. Download the `mssql-jdbc` JAR file from one of the following sources:

.. Download a version from the https://learn.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server[Microsoft JDBC Driver for SQL Server page].

.. Maven Central via `link:++https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.8.1.jre11/mssql-jdbc-12.8.1.jre11.jar++[mssql-jdbc]`.

.. Installation media recommended by the database vendor for the specific database in use.

. When running the unzipped distribution: Place the `mssql-jdbc` in {project_name}'s `providers` folder

. When running containers: Build a custom {project_name} image and add the JARs in the `providers` folder. When building a custom image for the {project_name} Operator, those images need to be optimized images with all build-time options of {project_name} set.
+
A minimal Containerfile to build an image which can be used with the {project_name} Operator and includes Microsoft SQL Server JDBC drivers downloaded from Maven Central looks like the following:
+
[source,dockerfile,subs="attributes+"]
----
FROM quay.io/keycloak/keycloak:{containerlabel}
ADD --chown=keycloak:keycloak --chmod=644 https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.8.1.jre11/mssql-jdbc-12.8.1.jre11.jar /opt/keycloak/providers/mssql-jdbc.jar
# Setting the build parameter for the database:
ENV KC_DB=mssql
# Add all other build parameters needed, for example enable health and metrics:
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
# To be able to use the image with the {project_name} Operator, it needs to be optimized, which requires {project_name}'s build step:
RUN /opt/keycloak/bin/kc.sh build
----
+
See the link:{links_server_containers_url}[{links_server_containers_name}] {section} for details on how to build optimized images.

Then continue configuring the database as described in the next section.

endif::[]

== Configuring a database

For each supported database, the server provides some opinionated defaults to simplify database configuration. You complete the configuration by providing some key settings such as the database host and credentials.

The configuration can be set during a `build` command OR a `start` command:

. Using a `build` command followed by an optimized `start` command (recommended)
+
First, the minimum settings needed to connect to the database can be specified in `conf/keycloak.conf`:
+
----
# The database vendor.
db=postgres

# The username of the database user.
db-username=keycloak

# The password of the database user.
db-password=change_me

# Sets the hostname of the default JDBC URL of the chosen vendor
db-url-host=keycloak-postgres
----
+

Then, the following commands create a new and optimized server image based on the configuration options and start the server.
+
----
bin/kc.[sh|bat] build
bin/kc.[sh|bat] start --optimized
----
+

. Using *only a `start`* command (without `--optimized`)
+
[source,bash]
----
bin/kc.[sh|bat] start --db postgres --db-url-host keycloak-postgres --db-username keycloak --db-password change_me
----

WARNING: The examples above include the minimum settings needed to connect to the database but it exposes the database password and is not recommended. Use the `conf/keycloak.conf` as shown above, environment variables, or keystore for at least the password.

The default schema is `keycloak`, but you can change it by using the `db-schema` configuration option.

It is also possible to configure the database when link:{links_server_importExport_url}[{links_server_importExport_name}] or link:{links_server_bootstrap-admin-recovery_url}[{links_server_bootstrap-admin-recovery_name}]:
----
bin/kc.[sh|bat] import --help
bin/kc.[sh|bat] export --help
bin/kc.[sh|bat] bootstrap-admin --help
----

For more information, see link:{links_server_configuration_url}[{links_server_configuration_name}].

== Overriding default connection settings

The server uses JDBC as the underlying technology to communicate with the database. If the default connection settings are insufficient, you can specify a JDBC URL using the `db-url` configuration option.

The following is a sample command for a PostgreSQL database.

[source,bash]
----
bin/kc.[sh|bat] start --db postgres --db-url jdbc:postgresql://mypostgres/mydatabase
----

Be aware that you need to escape characters when invoking commands containing special shell characters such as `;` using the CLI, so you might want to set it in the configuration file instead.

== Overriding the default JDBC driver

The server uses a default JDBC driver accordingly to the database you chose.

To set a different driver you can set the `db-driver` with the fully qualified class name of the JDBC driver:

[source,bash]
----
bin/kc.[sh|bat] start --db postgres --db-driver=my.Driver
----

Regardless of the driver you set, the default driver is always available at runtime.

Only set this property if you really need to. For instance, when leveraging the capabilities from a JDBC Driver Wrapper for
a specific cloud database service.

== Configuring Unicode support for the database

Unicode support for all fields depends on whether the database allows VARCHAR and CHAR fields to use the Unicode character set.

* If these fields can be set, Unicode is likely to work, usually at the expense of field length.
* If the database only supports Unicode in the NVARCHAR and NCHAR fields, Unicode support for all text fields is unlikely to work because the server schema uses VARCHAR and CHAR fields extensively.

The database schema provides support for Unicode strings only for the following special fields:

* *Realms*: display name, HTML display name, localization texts (keys and values)

* *Federation* Providers: display name

* *Users*: username, given name, last name, attribute names and values

* *Groups*: name, attribute names and values

* *Roles*: name

* Descriptions of objects

Otherwise, characters are limited to those contained in database encoding, which is often 8-bit. However, for some database systems, you can enable UTF-8 encoding of Unicode characters and use the full Unicode character set in all text fields. For a given database, this choice might result in a shorter maximum string length than the maximum string length supported by 8-bit encodings.

=== Configuring Unicode support for an Oracle database

Unicode characters are supported in an Oracle database if the database was created with Unicode support in the VARCHAR and CHAR fields. For example, you configured AL32UTF8 as the database character set. In this case, the JDBC driver requires no special settings.

If the database was not created with Unicode support, you need to configure the JDBC driver to support Unicode characters in the special fields. You configure two properties. Note that you can configure these properties as system properties or as connection properties.

. Set `oracle.jdbc.defaultNChar` to `true`.

. Optionally, set `oracle.jdbc.convertNcharLiterals` to `true`.
+
[NOTE]
====
For details on these properties and any performance implications, see the Oracle JDBC driver configuration documentation.
====

=== Unicode support for a Microsoft SQL Server database

Unicode characters are supported only for the special fields for a Microsoft SQL Server database. The database requires no special settings.

The `sendStringParametersAsUnicode` property of JDBC driver should be set to `false` to significantly improve performance. Without this parameter,
the Microsoft SQL Server might be unable to use indexes.

=== Configuring Unicode support for a MySQL database

Unicode characters are supported in a MySQL database if the database was created with Unicode support in the VARCHAR and CHAR fields when using the CREATE DATABASE command.

Note that the utf8mb4 character set is not supported due to different storage requirements for the utf8 character set. See MySQL documentation for details. In that situation, the length restriction on non-special fields does not apply because columns are created to accommodate the number of characters, not bytes.  If the database default character set does not allow Unicode storage, only the special fields allow storing Unicode values.

. Start MySQL Server.
. Under JDBC driver settings, locate the *JDBC connection settings*.
. Add this connection property: `characterEncoding=UTF-8`

=== Configuring Unicode support for a PostgreSQL database

Unicode is supported for a PostgreSQL database when the database character set is UTF8. Unicode characters can be used in any field with no reduction of field length for non-special fields. The JDBC driver requires no special settings. The character set is determined when the PostgreSQL database is created.

. Check the default character set for a PostgreSQL cluster by entering the following SQL command.
+
[source]
----
show server_encoding;
----

. If the default character set is not UTF 8, create the database with the UTF8 as the default character set using a command such as:

+
[source]
----
create database keycloak with encoding 'UTF8';
----

[[preparing-keycloak-for-amazon-aurora-postgresql]]
== Preparing for Amazon Aurora PostgreSQL

When using Amazon Aurora PostgreSQL, the https://github.com/awslabs/aws-advanced-jdbc-wrapper[Amazon Web Services JDBC Driver] offers additional features like transfer of database connections when a writer instance changes in a Multi-AZ setup.
This driver is not part of the distribution and needs to be installed before it can be used.

To install this driver, apply the following steps:

. When running the unzipped distribution: Download the JAR file from the https://github.com/awslabs/aws-advanced-jdbc-wrapper/releases/[Amazon Web Services JDBC Driver releases page] and place it in {project_name}'s `providers` folder.

. When running containers: Build a custom {project_name} image and add the JAR in the `providers` folder.
+
A minimal Containerfile to build an image which can be used with the {project_name} Operator looks like the following:
+
[source,dockerfile,subs="attributes+"]
----
FROM quay.io/keycloak/keycloak:{containerlabel}
ADD --chmod=0666 https://github.com/awslabs/aws-advanced-jdbc-wrapper/releases/download/2.5.6/aws-advanced-jdbc-wrapper-2.5.6.jar /opt/keycloak/providers/aws-advanced-jdbc-wrapper.jar
----
+
See the link:{links_server_containers_url}[{links_server_containers_name}] {section} for details on how to build optimized images, and the link:{links_operator_customizing-keycloak_url}[{links_operator_customizing-keycloak_name}] {section} on how to run optimized and non-optimized images with the {project_name} Operator.
. Configure {project_name} to run with the following parameters:
`db-url`:: Insert `aws-wrapper` to the regular PostgreSQL JDBC URL resulting in a URL like `+jdbc:aws-wrapper:postgresql://...+`.
`db-driver`:: Set to `software.amazon.jdbc.Driver` to use the AWS JDBC wrapper.

== Preparing for MySQL server

Beginning with MySQL 8.0.30, MySQL supports generated invisible primary keys for any InnoDB table that is created without an explicit primary key (more information https://dev.mysql.com/doc/refman/8.0/en/create-table-gipks.html[here]).
If this feature is enabled, the database schema initialization and also migrations will fail with the error message `Multiple primary key defined (1068)`.
You then need to disable it by setting the parameter `sql_generate_invisible_primary_key` to `OFF` in your MySQL server configuration before installing or upgrading {project_name}.

== Changing database locking timeout in a cluster configuration

Because cluster nodes can boot concurrently, they take extra time for database actions. For example, a booting server instance may perform some database migration, importing, or first time initializations. A database lock prevents start actions from conflicting with each other when cluster nodes boot up concurrently.

The maximum timeout for this lock is 900 seconds. If a node waits on this lock for more than the timeout, the boot fails. The need to change the default value is unlikely, but you can change it by entering this command:

[source,bash]
----
bin/kc.[sh|bat] start --spi-dblock--jpa--lock-wait-timeout 900
----

== Using Database Vendors with XA transaction support
{project_name} uses non-XA transactions and the appropriate database drivers by default.

If you wish to use the XA transaction support offered by your driver, enter the following command:

[source,bash]
----
bin/kc.[sh|bat] build --db=<vendor> --transaction-xa-enabled=true
----

{project_name} automatically chooses the appropriate JDBC driver for your vendor.

NOTE: Certain vendors, such as Azure SQL and MariaDB Galera, do not support or rely on the XA transaction mechanism.

XA recovery defaults to enabled and will use the file system location `KEYCLOAK_HOME/data/transaction-logs` to store transaction logs.

NOTE: Enabling XA transactions in a containerized environment does not fully support XA recovery unless stable storage is available at that path.

== Setting JPA provider configuration option for migrationStrategy

To setup the JPA migrationStrategy (manual/update/validate) you should setup JPA provider as follows:

.Setting the `migration-strategy` for the `quarkus` provider of the `connections-jpa` SPI
[source,bash]
----
bin/kc.[sh|bat] start --spi-connections--jpa--quarkus-migration-strategy=manual
----

If you want to get a SQL file for DB initialization, too, you have to add this additional SPI initializeEmpty (true/false):

.Setting the `initialize-empty` for the `quarkus` provider of the `connections-jpa` SPI
[source,bash]
----
bin/kc.[sh|bat] start --spi-connections--jpa--quarkus-initialize-empty=false
----

In the same way the migrationExport to point to a specific file and location:

.Setting the `migration-export` for the `quarkus` provider of the `connections-jpa` SPI
[source,bash]
----
bin/kc.[sh|bat] start --spi-connections--jpa--quarkus-migration-export=<path>/<file.sql>
----

For more information, check the link:{upgrading_guide_link}#_migrate_db[Migrating the database] documentation.


== Relevant options

[cols="12a,4",role="options"]
|===
| |Value

|
[.options-key]#`+db+`# [.none]#icon:tools[role=options-build]#

[.options-description]#The database vendor.#

[role="options-extended"]
--
[.options-description-extended]#In production mode the default value of `dev-file` is deprecated, you should explicitly specify the db instead.#

*CLI:* `+--db+` +
*Env:* `+KC_DB+`
--



|
`+dev-file+` (default), `+dev-mem+`, `+mariadb+`, `+mssql+`, `+mysql+`, `+oracle+`, `+postgres+`

|
[.options-key]#`+db-debug-jpql+`# 

[.options-description]#Add JPQL information as comments to SQL statements to debug JPA SQL statement generation.#

[role="options-extended"]
--


*CLI:* `+--db-debug-jpql+` +
*Env:* `+KC_DB_DEBUG_JPQL+`
--



|
`+true+`, `+false+` (default)

|
[.options-key]#`+db-driver+`# [.none]#icon:tools[role=options-build]#

[.options-description]#The fully qualified class name of the JDBC driver.#

[role="options-extended"]
--
[.options-description-extended]#If not set, a default driver is set accordingly to the chosen database.#

*CLI:* `+--db-driver+` +
*Env:* `+KC_DB_DRIVER+`
--



|

|
[.options-key]#`+db-log-slow-queries-threshold+`# 

[.options-description]#Log SQL statements slower than the configured threshold with logger org.#

[role="options-extended"]
--
[.options-description-extended]#hibernate.SQL_SLOW and log-level info.#

*CLI:* `+--db-log-slow-queries-threshold+` +
*Env:* `+KC_DB_LOG_SLOW_QUERIES_THRESHOLD+`
--



|[.options-default]#`+10000+`# (default)

|
[.options-key]#`+db-password+`# 

[.options-description]#The password of the database user.#

[role="options-extended"]
--


*CLI:* `+--db-password+` +
*Env:* `+KC_DB_PASSWORD+`
--



|

|
[.options-key]#`+db-pool-initial-size+`# 

[.options-description]#The initial size of the connection pool.#

[role="options-extended"]
--


*CLI:* `+--db-pool-initial-size+` +
*Env:* `+KC_DB_POOL_INITIAL_SIZE+`
--



|

|
[.options-key]#`+db-pool-max-size+`# 

[.options-description]#The maximum size of the connection pool.#

[role="options-extended"]
--


*CLI:* `+--db-pool-max-size+` +
*Env:* `+KC_DB_POOL_MAX_SIZE+`
--



|[.options-default]#`+100+`# (default)

|
[.options-key]#`+db-pool-min-size+`# 

[.options-description]#The minimal size of the connection pool.#

[role="options-extended"]
--


*CLI:* `+--db-pool-min-size+` +
*Env:* `+KC_DB_POOL_MIN_SIZE+`
--



|

|
[.options-key]#`+db-schema+`# 

[.options-description]#The database schema to be used.#

[role="options-extended"]
--


*CLI:* `+--db-schema+` +
*Env:* `+KC_DB_SCHEMA+`
--



|

|
[.options-key]#`+db-url+`# 

[.options-description]#The full database JDBC URL.#

[role="options-extended"]
--
[.options-description-extended]#If not provided, a default URL is set based on the selected database vendor. For instance, if using `postgres`, the default JDBC URL would be `jdbc:postgresql://localhost/keycloak`.#

*CLI:* `+--db-url+` +
*Env:* `+KC_DB_URL+`
--



|

|
[.options-key]#`+db-url-database+`# 

[.options-description]#Sets the database name of the default JDBC URL of the chosen vendor.#

[role="options-extended"]
--
[.options-description-extended]#If the `db-url` option is set, this option is ignored.#

*CLI:* `+--db-url-database+` +
*Env:* `+KC_DB_URL_DATABASE+`
--



|

|
[.options-key]#`+db-url-host+`# 

[.options-description]#Sets the hostname of the default JDBC URL of the chosen vendor.#

[role="options-extended"]
--
[.options-description-extended]#If the `db-url` option is set, this option is ignored.#

*CLI:* `+--db-url-host+` +
*Env:* `+KC_DB_URL_HOST+`
--



|

|
[.options-key]#`+db-url-port+`# 

[.options-description]#Sets the port of the default JDBC URL of the chosen vendor.#

[role="options-extended"]
--
[.options-description-extended]#If the `db-url` option is set, this option is ignored.#

*CLI:* `+--db-url-port+` +
*Env:* `+KC_DB_URL_PORT+`
--



|

|
[.options-key]#`+db-url-properties+`# 

[.options-description]#Sets the properties of the default JDBC URL of the chosen vendor.#

[role="options-extended"]
--
[.options-description-extended]#Make sure to set the properties accordingly to the format expected by the database vendor, as well as appending the right character at the beginning of this property value. If the `db-url` option is set, this option is ignored.#

*CLI:* `+--db-url-properties+` +
*Env:* `+KC_DB_URL_PROPERTIES+`
--



|

|
[.options-key]#`+db-username+`# 

[.options-description]#The username of the database user.#

[role="options-extended"]
--


*CLI:* `+--db-username+` +
*Env:* `+KC_DB_USERNAME+`
--



|

|
[.options-key]#`+transaction-xa-enabled+`# [.none]#icon:tools[role=options-build]#

[.options-description]#If set to true, XA datasources will be used.#

[role="options-extended"]
--


*CLI:* `+--transaction-xa-enabled+` +
*Env:* `+KC_TRANSACTION_XA_ENABLED+`
--



|
`+true+`, `+false+` (default)


|===
