chmonitor
Getting Started

ClickHouse user & grants

Create a minimal read-only ClickHouse user for chmonitor, with optional action grants and a recommended monitoring profile.

chmonitor needs a ClickHouse user with at minimum SELECT on system.*. Do not use an admin account for a shared dashboard.

Connecting a firewalled ClickHouse to Cloud?

If your ClickHouse is behind a firewall and you use the hosted Cloud, see Connect a firewalled ClickHouse for how to reach it without a brittle IP allowlist (Cloudflare Tunnel, dedicated egress IPs, or a jump host).

Copy & paste: pick a permission level

Toggle the features you need — the SQL and XML output updates automatically. Replace your-password before running. The monitoring_profile body is in the recommended profile section below.

Select features

CREATE USER monitoring
  IDENTIFIED WITH sha256_password BY 'your-password'
  HOST ANY;

-- System tables (metrics, queries, merges, replicas, …)
GRANT SELECT ON system.* TO monitoring;
-- Required for some merge-aware queries
GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring;

The static reference tabs below show every combination individually if you prefer to copy from them directly.

-- Monitoring dashboards only. Cannot kill queries, optimize, or mutate data.
CREATE USER monitoring
  IDENTIFIED WITH sha256_password BY 'your-password'
  HOST ANY;

-- All system tables (metrics, queries, merges, replicas, …)
GRANT SELECT ON system.* TO monitoring;

-- Required for some merge-aware queries
GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring;
-- Monitoring dashboards + Data Explorer (query any table in any database).
-- SELECT ON *.* covers system.* as well — use only if you trust this account
-- to read all your databases.
CREATE USER monitoring
  IDENTIFIED WITH sha256_password BY 'your-password'
  HOST ANY;

GRANT SELECT ON *.* TO monitoring;
GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring;
-- Read-only monitoring, plus Kill Query and Optimize Table actions.
-- AGENT_ENABLE_CONTROL_TOOLS=true is also required for the AI agent to use these.
CREATE USER monitoring
  IDENTIFIED WITH sha256_password BY 'your-password'
  HOST ANY;

GRANT SELECT ON system.* TO monitoring;
GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring;
GRANT KILL QUERY ON *.* TO monitoring;
GRANT OPTIMIZE ON *.* TO monitoring;
<!-- /etc/clickhouse-server/users.d/monitoring.xml -->
<clickhouse>
  <users>
    <monitoring>
      <password_sha256_hex>REPLACE_WITH_SHA256_OF_YOUR_PASSWORD</password_sha256_hex>
      <networks><ip>::/0</ip></networks>
      <profile>monitoring_profile</profile>
      <grants>
        <query>GRANT SELECT ON system.*</query>
        <query>GRANT CREATE TEMPORARY TABLE ON *.*</query>
      </grants>
    </monitoring>
  </users>
</clickhouse>

Generate the hash: echo -n 'your-password' | sha256sum. See the recommended profile for the monitoring_profile body.

<!-- /etc/clickhouse-server/users.d/monitoring.xml -->
<!-- SELECT ON *.* covers system.* and every user database. -->
<clickhouse>
  <users>
    <monitoring>
      <password_sha256_hex>REPLACE_WITH_SHA256_OF_YOUR_PASSWORD</password_sha256_hex>
      <networks><ip>::/0</ip></networks>
      <profile>monitoring_profile</profile>
      <grants>
        <query>GRANT SELECT ON *.*</query>
        <query>GRANT CREATE TEMPORARY TABLE ON *.*</query>
      </grants>
    </monitoring>
  </users>
</clickhouse>

Generate the hash: echo -n 'your-password' | sha256sum. Run SYSTEM RELOAD CONFIG or restart ClickHouse after editing.

<!-- /etc/clickhouse-server/users.d/monitoring.xml -->
<!-- Read-only monitoring, plus Kill Query and Optimize Table. -->
<clickhouse>
  <users>
    <monitoring>
      <password_sha256_hex>REPLACE_WITH_SHA256_OF_YOUR_PASSWORD</password_sha256_hex>
      <networks><ip>::/0</ip></networks>
      <profile>monitoring_profile</profile>
      <grants>
        <query>GRANT SELECT ON system.*</query>
        <query>GRANT CREATE TEMPORARY TABLE ON *.*</query>
        <query>GRANT KILL QUERY ON *.*</query>
        <query>GRANT OPTIMIZE ON *.*</query>
      </grants>
    </monitoring>
  </users>
</clickhouse>

Generate the hash: echo -n 'your-password' | sha256sum. AGENT_ENABLE_CONTROL_TOOLS=true is also required for the AI agent to use Kill Query / Optimize.

Roles let you manage grants centrally and assign them to multiple users. Create the role via SQL first, then reference it from the user XML.

Step 1 — create the role (run once in a ClickHouse client):

CREATE ROLE IF NOT EXISTS monitoring_role;
GRANT SELECT ON system.* TO monitoring_role;
GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring_role;

-- Optional: expand to Explorer or action support
-- GRANT SELECT ON *.* TO monitoring_role;
-- GRANT KILL QUERY ON *.* TO monitoring_role;
-- GRANT OPTIMIZE ON *.* TO monitoring_role;

Step 2 — user config (/etc/clickhouse-server/users.d/monitoring.xml):

<clickhouse>
  <users>
    <monitoring>
      <password_sha256_hex>REPLACE_WITH_SHA256_OF_YOUR_PASSWORD</password_sha256_hex>
      <networks><ip>::/0</ip></networks>
      <profile>monitoring_profile</profile>
      <grants>
        <query>GRANT monitoring_role TO monitoring</query>
      </grants>
    </monitoring>
  </users>
</clickhouse>

Generate the hash: echo -n 'your-password' | sha256sum. Run SYSTEM RELOAD CONFIG after editing the XML. Update grants on the role and they apply to all users holding it.

Minimum: read-only monitoring user

This user can view all monitoring pages. It cannot kill queries, run optimizations, or mutate data.

-- Create the user
CREATE USER monitoring
  IDENTIFIED WITH sha256_password BY 'your-password'
  HOST ANY;

-- Grant read-only access to system tables
GRANT SELECT ON system.* TO monitoring;

-- Allow temporary tables (required for some merge-aware queries)
GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring;

Optional: Data Explorer (query any table)

The Data Explorer lets you run SQL against any table in your ClickHouse instance, not just system.*. To enable it, grant SELECT on all databases:

-- Lets the monitoring user read every table in every database.
-- Use only if you trust this account to access all your data.
GRANT SELECT ON *.* TO monitoring;

SELECT ON *.* is a superset of SELECT ON system.*, so you do not need both.

Optional grants for actions

Add these only if you want operators to use the corresponding actions from the UI.

-- Kill Query action (Running Queries page)
GRANT KILL QUERY ON *.* TO monitoring;

-- Optimize Table action (Data Explorer page)
GRANT OPTIMIZE ON *.* TO monitoring;

Control tools are off by default

AGENT_ENABLE_CONTROL_TOOLS must also be set to true for the AI agent to use kill/optimize. Keep it false (the default) on public or shared deployments.

Optional: self-tracking events table

chmonitor can write dashboard pageview events to a ClickHouse table (system.monitoring_events by default). Change EVENTS_TABLE_NAME to a table in your own database if you prefer not to write to system.*.

If you enable this, the monitoring user needs write access to that table:

GRANT SELECT, INSERT
  ON your_database.monitoring_events
  TO monitoring;

Per-feature grants checklist

GRANT SELECT ON system.* covers the majority of the dashboard. Some features read tables that require additional grants or depend on optional system tables that are only present when a subsystem is configured.

Always required

Dashboard featureSystem tables usedGrant
Overview metricssystem.metrics, system.asynchronous_metricsSELECT ON system.*
Running queriessystem.processesSELECT ON system.*
Active mergessystem.mergesSELECT ON system.*
Replica statussystem.replicasSELECT ON system.*
Disks & storagesystem.disks, system.partsSELECT ON system.*
Tables listsystem.tables, system.columnsSELECT ON system.*
Clusterssystem.clustersSELECT ON system.*
Mutationssystem.mutationsSELECT ON system.*
Replication queuesystem.replication_queueSELECT ON system.*
Settings / users / rolessystem.settings, system.users, system.rolesSELECT ON system.*
Warningssystem.warningsSELECT ON system.*
Errorssystem.errorsSELECT ON system.*
Dictionariessystem.dictionariesSELECT ON system.*

Requires system.query_log (enabled by default in most setups)

FeatureTablesGrant
Query historysystem.query_logSELECT ON system.*
Slow / expensive queriessystem.query_logSELECT ON system.*
Failed queriessystem.query_logSELECT ON system.*
Common errorssystem.errorsSELECT ON system.*
Top tables / columns by usagesystem.query_logSELECT ON system.*

Optional — tables present only when the subsystem is configured

These pages show a "table not available" notice when the underlying table does not exist. No error is raised.

FeatureRequired tableNotes
Query thread analysis / parallelizationsystem.query_thread_logEnable in ClickHouse server config
Query profilersystem.processors_profile_logEnable in ClickHouse server config
Query views logsystem.query_views_logAvailable from ClickHouse 22.4+
Query cachesystem.query_cacheAvailable from ClickHouse 23.5+
User processessystem.user_processesAvailable from ClickHouse 23.3+
Merge performancesystem.part_logEnable part_log in server config
Part logsystem.part_logEnable part_log in server config
Query metric logsystem.query_metric_logEnable in ClickHouse server config
Detached partssystem.detached_partsAlways exists; may be empty
Dropped tablessystem.dropped_tablesAvailable from ClickHouse 23.x+
Distributed DDL queuesystem.distributed_ddl_queueOnly on clusters using DDL via ZooKeeper/Keeper
Movessystem.movesOnly when tiered storage / volume moves are active
Replicated fetchessystem.replicated_fetchesOnly on replicated clusters
View refreshessystem.view_refreshesOnly when Refreshable Materialized Views are in use
Skip indexes (Data Explorer)system.data_skipping_indicesAvailable from ClickHouse 22.x+
Login attempts / sessionssystem.session_logEnable in ClickHouse server config
Text logsystem.text_logEnable text_log in server config
Crash logsystem.crash_logAlways exists on supported versions
Backupssystem.backup_logOptional. Only exists when backups are configured.
Error logsystem.error_logOptional. Enable error_log in server config.

ClickHouse Keeper / ZooKeeper (all optional)

All Keeper pages are optional: true — they silently degrade to a notice when Keeper is not configured.

FeatureRequired tableNotes
Keeper overviewsystem.zookeeper_infoRequires Keeper/ZooKeeper
Keeper connectionssystem.zookeeper_connectionRequires Keeper/ZooKeeper
Keeper watchessystem.zookeeper_watchesRequires Keeper/ZooKeeper
Keeper logsystem.zookeeper_logRequires Keeper/ZooKeeper
Keeper connection logsystem.zookeeper_connection_logAvailable from ClickHouse 25.8+
ZooKeeper data browsersystem.zookeeperRequires Keeper/ZooKeeper

No special grants are needed for Keeper tables — SELECT ON system.* covers them. They simply do not exist when Keeper is not running.

Kafka (optional)

FeatureRequired tableNotes
Kafka consumerssystem.kafka_consumersOnly exists when Kafka engine tables are present

Action grants (not SELECT)

ActionGrant needed
Kill Query (Running Queries page / AI agent)GRANT KILL QUERY ON *.* TO monitoring;
Optimize Table (Data Explorer / AI agent)GRANT OPTIMIZE ON *.* TO monitoring;
Create temporary tables (some merge queries)GRANT CREATE TEMPORARY TABLE ON *.* TO monitoring;

Optional: ClickHouse Keeper / ZooKeeper access

system.zookeeper is available only when ZooKeeper or ClickHouse Keeper is configured. No special grants are needed — SELECT ON system.* covers it.

Multi-host setup

Each ClickHouse host in a multi-host deployment can have its own user and password. Use comma-separated values in the same position across all four variables:

CLICKHOUSE_HOST=https://prod-a:8443,https://prod-b:8443
CLICKHOUSE_USER=monitoring,monitoring
CLICKHOUSE_PASSWORD=secret-a,secret-b
CLICKHOUSE_NAME=prod-a,prod-b

CLICKHOUSE_HOST defines the host count. CLICKHOUSE_USER and CLICKHOUSE_PASSWORD may be a single shared value or one value per host position. CLICKHOUSE_NAME is optional. Position N maps to host index N.

Create a monitoring profile to enable query caching and the experimental analyzer:

<!-- /etc/clickhouse-server/users.d/monitoring_profile.xml -->
<clickhouse>
  <profiles>
    <monitoring_profile>
      <allow_experimental_analyzer>1</allow_experimental_analyzer>

      <!-- Optional: reduce repeated load from dashboard queries -->
      <use_query_cache>1</use_query_cache>
      <query_cache_ttl>50</query_cache_ttl>
      <query_cache_max_entries>0</query_cache_max_entries>
      <query_cache_system_table_handling>save</query_cache_system_table_handling>
      <query_cache_nondeterministic_function_handling>save</query_cache_nondeterministic_function_handling>
    </monitoring_profile>
  </profiles>

  <users>
    <monitoring>
      <profile>monitoring_profile</profile>
    </monitoring>
  </users>
</clickhouse>

On this page