---
title: "Step 2: Prepare data services"
description: Create the four SQL Server databases for OpenLM Platform and check that MongoDB, Kafka, and Redis are reachable from the cluster.
product: OpenLM Platform
---

Create the SQL databases and prove that pods can reach every data service, **before** the installation depends on them. OpenLM Platform keeps all of its data in four services that you provide.

The commands on this page load their variables from `openlm-install.env`, the file you created from the [installation worksheet](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/before-you-start/worksheet).

```bash
source ./openlm-install.env
```

## 2.1 Create four SQL Server databases

OpenLM Platform uses these four SQL Server databases:

| Database | Name with the default prefix | What it holds | Who creates the tables |
|---|---|---|---|
| Identity | `openlm_identity` | Users, sign-in clients, tokens | The identity service, on first start |
| Operational | `openlm_operational_none` | Licenses, servers, usage: the main data | The services, on first start |
| Reporting | `openlm_reporting` | Data prepared for reports and Power BI | Tables by the data-processing jobs, views by the [reporting scripts](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/install/step-8-first-sign-in#83-install-the-reporting-views) |
| DSS | `openlm_dss` | Directory synchronization | The DSS service, on first start |

:::note[Why "_none"?]
The operational database name is built from a prefix and a tenant name. A self-hosted installation has one tenant, called `none`, so the name ends in `_none`. Don't leave the suffix out.
:::

Create them signed in as an administrator. Run the `CREATE DATABASE` statements in SQL Server Management Studio (SSMS) or another SQL Server client, or with `sqlcmd`:

```bash
for db in identity operational_none reporting dss; do
  sqlcmd -S "$SQL_HOST,$SQL_PORT" -U "<admin-login>" -C -Q "CREATE DATABASE [${DB_PREFIX}_${db}]"
done
```

Then create the application login (`$SQL_USER`) and give it ownership of all four databases. On SQL Server, create the login once, in `master`:

```sql
CREATE LOGIN [openlm_app] WITH PASSWORD = '<your SQL_PASSWORD>';   -- your SQL_USER
```

Then run this once per database, with the database name in place of `<db>`:

```sql
USE [<db>];
CREATE USER [openlm_app] FOR LOGIN [openlm_app];   -- your SQL_USER
ALTER ROLE db_owner ADD MEMBER [openlm_app];
```

On **Azure SQL Database** and **Amazon RDS**, create the databases from the cloud console or the `master` database instead, and grant `db_owner` the same way. Your [platform page](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/platforms/index) has the details.

:::tip[Check SQL]
Run this from inside the cluster, with the application login:

```bash
kubectl -n "$NS" run sqltest --rm -it --restart=Never \
  --image=mcr.microsoft.com/mssql/server:2022-latest -- \
  /opt/mssql-tools18/bin/sqlcmd -S "$SQL_HOST,$SQL_PORT" -U "$SQL_USER" -P "$SQL_PASSWORD" -C \
  -Q "SELECT name FROM sys.databases WHERE name LIKE '${DB_PREFIX}_%'"
```

It must list all four databases. The image is large (about 1.5 GB), so the first run can take a few minutes to start. `Login failed` means a wrong user or password. `timeout` means the network between the cluster and SQL Server is blocked: see [Networking](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/concepts/networking#data-services).

If the pod stays in `ImagePullBackOff`, your cluster can't pull from that registry. Mirror the image, or run the same command from any machine that reaches the database.
:::

## 2.2 MongoDB

You don't create anything in MongoDB: each service creates its own database on first start. The user in `MONGO_URI` needs permission to do that (`readWriteAnyDatabase` and `dbAdminAnyDatabase`, or `root`).

Follow two rules for the connection string:

- **No `/` at the end**: `mongodb://u:p@host:27017` is correct. `mongodb://u:p@host:27017/` silently breaks certain services.
- **Special characters in the password**: URL-encode `@ : / ? # %`, for example `@` becomes `%40`.

:::tip[Check MongoDB]
```bash
kubectl -n "$NS" run mongotest --rm -it --restart=Never \
  --image=public.ecr.aws/docker/library/mongo:7.0 -- \
  mongosh "$MONGO_URI" --quiet --eval "db.adminCommand({listDatabases:1}).ok"
```

It must print `1`.
:::

## 2.3 Kafka

You don't create anything in Kafka. During installation, OpenLM Platform creates about 130 topics itself, so the Kafka user needs permission to create topics. The broker setting `auto.create.topics.enable` isn't needed.

Check these Kafka settings:

- Plaintext listeners (port 9092) are the standard setup. If your Kafka only offers TLS or SASL listeners, tell OpenLM before you install.
- On a **single-broker** Kafka, set the default replication factor and `offsets.topic.replication.factor` to `1`, or consumer groups never start.
- Set the broker's message retention to 14 days: `log.retention.hours=336`. In this release, OpenLM Platform sets its own retention on some of its topics at every installation and upgrade, and the broker setting doesn't change them: 3 days and 1 GiB per partition on 22 topics, including the data-pipeline topics `broker-messages` and `incoming-brokers-messages`.
- The bootstrap address must be the **advertised** address that pods can reach. A broker that advertises `localhost` or a private IP of another network works for the first connection and then fails.

:::tip[Check Kafka]
```bash
kubectl -n "$NS" run kafkatest --rm -it --restart=Never \
  --image=apache/kafka:3.7.0 -- \
  /opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP" --list
```

It must finish without errors. An empty list is fine. If it stops responding and then times out, the advertised address isn't reachable from pods.

If the pod stays in `ImagePullBackOff`, your cluster can't pull from that registry. Mirror the image, or run the same command from any machine that reaches Kafka.
:::

## 2.4 Redis

You don't create anything in Redis. OpenLM Platform and the API gateway share one Redis, with different keys.

:::tip[Check Redis]
```bash
kubectl -n "$NS" run redistest --rm -it --restart=Never \
  --image=public.ecr.aws/docker/library/redis:7.2-alpine -- \
  sh -c "redis-cli -h $REDIS_HOST -p $REDIS_PORT -a '$REDIS_PASSWORD' $( [ "$REDIS_TLS" = true ] && echo --tls ) PING"
```

It must print `PONG`.
:::

:::tip[Check]
All four checks in this step passed: SQL Server lists four databases, MongoDB prints `1`, Kafka lists topics without an error, and Redis prints `PONG`.
:::
