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

# Database monitoring

> Monitor PostgreSQL, MongoDB, Redis and ClickHouse with a standard OpenTelemetry Collector — receiver configuration, how instances are identified, and what each chart needs.

The **Databases** section shows the health of your database servers: which
instances are reporting, the databases they hold, and how their connections,
throughput, cache and memory moved over the selected time range.

Four engines are supported: **PostgreSQL**, **MongoDB**, **Redis** and
**ClickHouse**. Choose one with the **Engine** selector in the toolbar.

<Info>
  **Before you start.** There is no database agent. A standard OpenTelemetry
  Collector (the contrib distribution) scrapes the database and sends its
  metrics to aiAxonIQ like any other metric. You need a Collector that can reach
  the database and a license key — see
  [Send data with OpenTelemetry](/send-data/otel/collector).
</Info>

<Note>
  **This is server health, not query monitoring.** Nothing reads
  `pg_stat_statements` or stores query digests, so there are no slow-query
  lists, execution plans, query history or connection-pool breakdowns here. The
  page lists those four as **Not served by the API yet** rather than
  approximating them. For the time your **application** spends in database
  calls, see **Databases** inside an [APM](/guides/apm/overview) project, which
  is built from your application's spans.
</Note>

## How the page reads your metrics

Two rules decide what appears, and knowing them saves most debugging.

**The engine is the metric-name prefix.** A metric named `postgresql.backends`
belongs to PostgreSQL, `redis.memory.used` to Redis. A receiver that renames its
metrics disappears from this page rather than showing up wrong.

**An instance is identified by the first of these attributes that is set**,
looked for on both the resource and the data point:

| Engine     | Instance identity, in order                                |
| :--------- | :--------------------------------------------------------- |
| PostgreSQL | `postgresql.host`, `server.address`, `service.instance.id` |
| MongoDB    | `mongodb.host`, `server.address`, `service.instance.id`    |
| Redis      | `redis.host`, `server.address`, `service.instance.id`      |
| ClickHouse | `clickhouse.host`, `server.address`, `service.instance.id` |

A metric carrying none of them is listed under the instance `unknown`.

The **Databases** card lists database names where the engine reports them:

| Engine     | Database name read from                                                                 |
| :--------- | :-------------------------------------------------------------------------------------- |
| PostgreSQL | `postgresql.database.name`                                                              |
| MongoDB    | `db.namespace`, or `database` from older receivers                                      |
| Redis      | No per-database dimension — the card lists the reporting instances instead, and says so |
| ClickHouse | No per-database dimension — the metrics are server-wide, and the card says so           |

<Warning>
  **Database metrics belong to your organization, not to a project.** They come
  from a Collector, not from an application, so they carry no project. The page
  always shows the whole organization's instances for the chosen engine.
</Warning>

## Configure the Collector

Add the receiver for each engine you run, then export the metrics pipeline to
aiAxonIQ. The receiver configurations below were measured against
`otel/opentelemetry-collector-contrib:0.151.0`; replace the host names,
credentials and database names with your own.

<Tabs>
  <Tab title="PostgreSQL">
    ```yaml theme={null}
    receivers:
      postgresql:
        endpoint: your-postgres-host:5432
        transport: tcp
        username: ${env:PG_USER}
        password: ${env:PG_PASSWORD}
        databases: [your_database]
        collection_interval: 30s
        tls:
          insecure: true   # only for a server without TLS; otherwise configure TLS
        # Three metrics the Databases page charts that the receiver leaves
        # off by default. Without them, three charts have no source.
        metrics:
          postgresql.deadlocks:
            enabled: true
          postgresql.sequential_scans:
            enabled: true
          postgresql.temp_files:
            enabled: true
    ```

    Give the scraping role `pg_monitor`:

    ```sql theme={null}
    CREATE ROLE otel_monitor LOGIN PASSWORD 'choose-a-password';
    GRANT pg_monitor TO otel_monitor;
    ```

    | Chart                 | Metric                                                                                   |
    | :-------------------- | :--------------------------------------------------------------------------------------- |
    | Connections           | `postgresql.backends`, per database                                                      |
    | Commits, Rollbacks    | `postgresql.commits`, `postgresql.rollbacks`, per database                               |
    | Cache hit ratio       | `postgresql.blocks_read` — hits and reads are one metric split by its `source` attribute |
    | Deadlocks             | `postgresql.deadlocks` — off by default                                                  |
    | Replication lag       | `postgresql.replication.data_delay` — needs replication                                  |
    | Database size         | `postgresql.db_size`, per database                                                       |
    | WAL                   | `postgresql.wal.age`, `.delay`, `.lag` — needs WAL archiving                             |
    | Scans                 | `postgresql.sequential_scans` (off by default), `postgresql.index.scans`                 |
    | Vacuum and temp files | `postgresql.table.vacuum.count`, `postgresql.temp_files` (off by default)                |
  </Tab>

  <Tab title="MongoDB">
    ```yaml theme={null}
    receivers:
      mongodb:
        hosts:
          - endpoint: your-mongo-host:27017
        username: ${env:MONGO_USER}
        password: ${env:MONGO_PASSWORD}
        collection_interval: 30s
        tls:
          insecure: true   # only for a server without TLS; otherwise configure TLS
    ```

    The scraping user needs the `clusterMonitor` role on `admin`.

    | Chart                      | Metric                                                             |
    | :------------------------- | :----------------------------------------------------------------- |
    | Connections                | `mongodb.connection.count`                                         |
    | Operations, Operation time | `mongodb.operation.count`, `mongodb.operation.time`, per operation |
    | Cache operations           | `mongodb.cache.operations`, by hit and miss                        |
    | Index access               | `mongodb.index.access.count`, per collection                       |
    | Memory                     | `mongodb.memory.usage`                                             |
    | Network I/O                | `mongodb.network.io.receive`, `mongodb.network.io.transmit`        |
    | Document operations        | `mongodb.document.operation.count`                                 |

    On a standalone instance the receiver logs
    `Failed to get replica set status: (NoReplicationEnabled)` once at startup.
    That is expected and does not affect these charts.
  </Tab>

  <Tab title="Redis">
    ```yaml theme={null}
    receivers:
      redis:
        endpoint: your-redis-host:6379
        password: ${env:REDIS_PASSWORD}   # omit if AUTH is off
        collection_interval: 30s
    ```

    Every Redis chart works with the receiver's defaults: Clients connected,
    Commands, Hit ratio, Memory used, Fragmentation, Evictions, Network I/O and
    Replication offset. Replication offset only moves where a replica is
    attached.
  </Tab>

  <Tab title="ClickHouse">
    There is no OpenTelemetry receiver for ClickHouse. It is scraped with the
    `sqlquery` receiver against its own system tables, and the charts expect
    three metric names — `clickhouse.metric`, `clickhouse.event` and
    `clickhouse.async` — each carrying the ClickHouse metric's own name in a
    `name` attribute:

    ```yaml theme={null}
    receivers:
      sqlquery/clickhouse:
        driver: clickhouse
        datasource: "clickhouse://${env:CH_USER}:${env:CH_PASSWORD}@your-clickhouse-host:9000"
        collection_interval: 30s
        queries:
          - sql: "SELECT metric AS name, toInt64(value) AS value FROM system.metrics WHERE metric IN ('Query','BackgroundPoolTask','BackgroundMergesAndMutationsPoolTask','MemoryTracking','TCPConnection','HTTPConnection','OpenFileForRead','OpenFileForWrite','PartsActive')"
            metrics:
              - metric_name: clickhouse.metric
                value_column: value
                attribute_columns: [name]
                value_type: int
                data_type: gauge
          - sql: "SELECT event AS name, toInt64(value) AS value FROM system.events WHERE event IN ('Query','SelectQuery','InsertQuery','FailedQuery','InsertedRows','InsertedBytes','MergedRows','MergedUncompressedBytes','SelectedRows','NetworkReceiveElapsedMicroseconds','NetworkSendElapsedMicroseconds')"
            metrics:
              - metric_name: clickhouse.event
                value_column: value
                attribute_columns: [name]
                value_type: int
                data_type: sum
                monotonic: true
          - sql: "SELECT metric AS name, toFloat64(value) AS value FROM system.asynchronous_metrics WHERE metric IN ('MemoryResident','Uptime','OSMemoryAvailable','OSMemoryTotal','LoadAverage1','LoadAverage5','LoadAverage15','MarkCacheBytes','UncompressedCacheBytes','jemalloc.resident')"
            metrics:
              - metric_name: clickhouse.async
                value_column: value
                attribute_columns: [name]
                value_type: double
                data_type: gauge
    ```

    Grant the scraping user `SELECT ON system.*`. The charts are Queries, Failed
    queries, Rows inserted, Memory tracked, Active parts, Active merges and
    Connections.
  </Tab>
</Tabs>

Then send the metrics pipeline to aiAxonIQ. Set `OIQ_ENDPOINT` to the base
endpoint for your deployment and `OIQ_LICENSE_KEY` to your license key:

| Deployment                               | Base endpoint                    |
| :--------------------------------------- | :------------------------------- |
| **aiAxonIQ Cloud**                       | `https://app.aiaxoniq.com/otlp`  |
| **Self-hosted** behind the bundled nginx | `https://app.<your-domain>/otlp` |

Both forms carry the `/otlp` prefix because nginx serves OTLP under it and
strips it before forwarding, so the receiver still sees `/v1/logs`. Dropping the
prefix is the most common setup mistake: the request reaches the dashboard
instead of the receiver and comes back as an HTML 404 rather than an ingest
error.

```yaml theme={null}
exporters:
  otlphttp/aiaxoniq:
    endpoint: ${env:OIQ_ENDPOINT}
    headers:
      X-License-Key: ${env:OIQ_LICENSE_KEY}

service:
  pipelines:
    metrics:
      receivers: [postgresql, redis]   # the receivers you configured above
      processors: [batch]
      exporters: [otlphttp/aiaxoniq]
```

**Expected result.** After the Collector's next scrape, the chosen engine's
**Instances** table lists your server and **Metrics reporting** is above zero.

## What the page shows

* **Instances**, **Databases** and **Metrics reporting** — how many instances,
  databases and distinct metrics reported in the window.
* An **Instances** table with host, metric and sample counts, and last seen.
* The **Databases** card described above.
* **Engine metrics** — the charts for the chosen engine, all loaded in one
  request.
* **Reported metrics** — every metric this engine's Collector actually sent in
  the window, with its type, latest value and unit. A unit marked
  *(inferred)* was guessed from the metric name because the receiver sent none.
* **Not served by the API yet** — the four statement-level views that do not
  exist.

## Troubleshooting

<AccordionGroup>
  <Accordion title="No instances reporting for an engine">
    Nothing with that engine's metric prefix arrived in the window. Check the
    **Reported metrics** table: if it is empty too, the problem is upstream —
    the Collector, its network path to aiAxonIQ, or the license key — not the
    charts. Confirm the receiver is listed in the Collector's `metrics`
    pipeline.
  </Accordion>

  <Accordion title="A chart says No samples in this window">
    There are three causes, and they need different fixes:

    1. **The metric is off by default.** Enable it in the receiver, as shown
       for PostgreSQL above.
    2. **The metric is conditional.** Replication lag and WAL report nothing on
       a standalone instance; the chart says so beneath it. That is a correct
       answer, not a fault.
    3. **Nothing is arriving at all.** See the previous entry.
  </Accordion>

  <Accordion title="Every instance is called unknown">
    None of the instance attributes for that engine is set on the metrics. Add
    `service.instance.id` with a `resource` processor, or use a receiver version
    that sets `server.address`.
  </Accordion>

  <Accordion title="ClickHouse shows nothing while the Collector runs">
    The page expects the three metric names `clickhouse.metric`,
    `clickhouse.event` and `clickhouse.async`, with a `name` attribute. A
    `sqlquery` configuration that names its metrics differently reports into a
    different prefix and does not appear here. Copy the configuration above.
  </Accordion>

  <Accordion title="The API refuses a request that names a project">
    Database metrics carry no project, so the database API answers `400` to a
    request that passes `projectId`, rather than returning the whole
    organization's data under a project's name. Drop `projectId` from the
    request.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Infrastructure and Kubernetes" icon="server" href="/guides/infrastructure/overview">
    Hosts, containers and the machines your databases run on.
  </Card>

  <Card title="Exploring metrics" icon="chart-line" href="/guides/metrics/overview">
    Chart any database metric the Collector sends.
  </Card>
</CardGroup>
