Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Documentation

Understand kbdiag, run your first check, and look up commands by problem.

Start here

Start with status and sessions. If you already have a problem in front of you, pick a command from the capabilities page or follow a troubleshooting scenario.

Troubleshooting: lock waits and long-running SQL

1 - About kbdiag

Read-only command-line diagnostics for KingbaseES: a verdict, the evidence and the next step.

What problem does it solve?

When something feels wrong with a database, the first questions are usually the same: who is connected, who is waiting for a lock and who blocks them, which transaction has been open too long, whether a standby’s slot is piling up WAL. Answering them means remembering system views and joining them by hand.

kbdiag packages those questions into commands. Each command runs one read-only look at a live instance and prints a verdict, the evidence it is based on, and the next command to run.

Who is it for?

ReaderStart withWhat you get
Operationsstatus, sessionsInstance facts, connection pressure, sessions left idle in transaction
DBAslocks, session <pid>, txnWho blocks whom, what a session holds, old and prepared transactions
Monitoring scriptsany command, --jsonA verdict in the exit code and a stable JSON report

Look, query, diagnose

  1. Look: one command gives one fact, such as the instance’s role or its connection usage (status).
  2. Query: a focused command looks at one dimension in depth, such as lock waits (locks) or one session (session <pid>).
  3. Diagnose: correlating several dimensions into a root cause is planned for later versions. This version does look and query; each finding’s verify line tells you which query to run next.

Runtime and requirements

  • KingbaseES V8R6 (tested on V008R006C009B0014), standalone or repmgr primary/standby.
  • One static Linux binary (amd64 or arm64). It speaks the wire protocol itself: no ksql, no runtime, no service.
  • Run it on the database host as the kingbase OS user over the local socket for the full picture. Other accounts and TCP work too; what they cannot see is reported, not hidden.
  • repmgr is optional.

Operating boundaries

  • Read-only. Every connection is a read-only transaction with a lock_timeout. Suggested fixes, such as ROLLBACK PREPARED, are printed for you to review and never run.
  • No pretend OK. When something the verdict depends on could not be collected or seen, and nothing visible is WARN or FAIL, the verdict is UNKNOWN (exit 3), not OK.
  • One look, not monitoring. Each run is a single sample. A clean result says nothing about a moment ago or a moment later.

kbdiag 2.0 is a Go rewrite. The shell toolkit (v1.x) is frozen; its other commands (health check, reports, performance and advisors) are available in release v1.0.0.

Next

Run your first check · Explore capabilities · View source

2 - Capabilities

Choose a command by the question you need answered: instance, sessions, locks, transactions, waits, replication slots.

Start with the question you need to answer. Examples assume the binary is at ~/kbdiag; see the user manual for every flag and output field.

Instance

What is this instance, and do its basics hold?

~/kbdiag status

Version, role (primary / standby), uptime, connections, which standbys it sends WAL to or where a standby receives WAL from, database sizes, and the disk holding the data directory. FAIL when every connection ordinary users may open is taken (max_connections less superuser_reserved_connections); WARN when a standby is not receiving WAL.

→ status

Sessions

Who holds the connections, which sessions are doing something, and what is one session doing?

~/kbdiag sessions
~/kbdiag session <pid>

sessions counts the connections by user, database, application and client, then lists the client sessions that are not idle, longest transaction first. It warns about sessions idle in transaction for more than 300 seconds. session <pid> shows one session in full: who it is, its whole SQL, the lock it waits for and who blocks it, whom it blocks and what it holds.

→ sessions · session

Locks

Who is waiting for a lock, and which session blocks them?

~/kbdiag locks

The blockers come first, the one blocking the most sessions at the top, then every waiting session, longest wait first. Each wait over 10 seconds is a WARN naming its direct blocker, and the verify line points to the blocker’s session. When a chain is several sessions long, follow it one hop at a time.

→ locks · Scenario: lock waits

Transactions

Who holds back the vacuum horizon: a transaction open too long, or a forgotten prepared (2PC) transaction?

~/kbdiag txn

The oldest transaction id first, with the sessions or prepared transaction holding it, then the open transactions and prepared ones. Open transactions WARN at 300 seconds and prepared transactions at 900, with a ROLLBACK PREPARED / COMMIT PREPARED suggestion printed for you to decide. Prepared transactions live on the primary; on a standby they are reported as not applicable.

→ txn

Waits

What are sessions waiting on right now?

~/kbdiag waits

The sessions doing something, grouped by wait event and state with their PIDs, biggest pile first. Idle sessions and background processes idling in their main loop are only counted. It summarizes without thresholds; use locks for how long and on whom.

→ waits · Scenario: long-running SQL

Replication slots

Is a slot keeping WAL for a standby that is gone?

~/kbdiag slots

Each slot with its consumer, the WAL it keeps and its xmin. An inactive slot keeps WAL and, with an xmin, holds back vacuum, so it is a WARN at once. The verify line sends you to status on the slot’s downstream node to check whether it still receives WAL. kbdiag never drops a slot.

→ slots

Script integration

Every command sets its exit code from the verdict and supports --json:

~/kbdiag --json locks
echo $?   # 0 OK, 1 WARN, 2 FAIL, 3 UNKNOWN, 64 usage error, 69 cannot connect

UNKNOWN means something could not be collected or seen, so kbdiag will not claim OK. 69 only means the connection failed; a database that accepts the connection but cannot answer is UNKNOWN. See exit codes.

Not in this version

Replication lag, repmgr cluster checks, slow-SQL history, vacuum and bloat, deadlock history and correlated diagnosis are not in kbdiag 2.0 yet. The frozen shell toolkit v1.0.0 still has health checks and reports if you need them.

3 - Your first check

Build the binary, install it on the database host, connect, and read the verdict and exit code.

Build kbdiag once, copy it to the KingbaseES host, and run status and sessions. Then decide what needs a closer look.

1. Prepare

  • A running KingbaseES V8R6 instance (tested on V008R006C009B0014).
  • Access to the kingbase OS user on the database host.
  • A machine with Go (the version in the repository’s go.mod) and git, to build the binary. It can be your laptop; the database host needs nothing but the binary.

2. Build and install

On the build machine:

git clone https://github.com/Kevin-wenyu/kbdiag.git
cd kbdiag
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=$(git describe --tags --match 'v2*' --always)" -o kbdiag ./cmd/kbdiag
scp kbdiag kingbase@db-host:~/kbdiag

Use GOARCH=arm64 for ARM hosts. The result is one static file with no runtime dependencies, so an offline host only needs the file copied over.

On the database host:

sudo -iu kingbase
chmod +x ~/kbdiag
~/kbdiag --version

3. Connect

By default kbdiag connects over the local socket /tmp/.s.KINGBASE.54321 to database test as user system, the way ksql test system does. Change the target with flags:

FlagDefault
--host/tmp (socket directory); a host name or IP for TCP
-p, --port54321
-d, --dbnametest
-U, --usersystem
--timeout10s per query

The password comes from PGPASSWORD or ~/.pgpass. If kbdiag cannot connect, it prints the error and exits with 69; check the port, socket directory and sys_hba.conf before anything else.

An account without a monitoring role cannot see other sessions’ state, timings or SQL. kbdiag lists those fields under redacted and answers UNKNOWN rather than OK; grant sys_monitor or use system for the full picture.

4. Run your first checks

~/kbdiag status
echo "exit code: $?"
~/kbdiag sessions
echo "exit code: $?"

Read $? right after the command; the next command replaces it. status tells you what the instance is and whether its basics hold: connections, replication, disk. sessions shows who holds the connections and which sessions are doing something, and warns about sessions left idle in transaction.

5. Read the verdict and exit code

The first line of every report carries the verdict, and the exit code says the same thing:

Exit codeVerdictNext step
0OKNothing crossed a threshold in this sample
1WARNNothing is broken yet, but it will be if left alone: read each finding and run its verify command
2FAILSame, now: the application is already affected
3UNKNOWNSomething could not be collected or seen; check privileges and the redacted list
64Usage errorCheck the command and flags
69Cannot connectCheck the connection first; nothing was looked at

A WARN or FAIL finding wins over UNKNOWN: if kbdiag found a problem in what it could see, it says so.

Read a real result line by line

6. Follow the evidence

You seeNext commandLook for
A lock wait~/kbdiag session <blocker pid>What the blocker is doing and how long its transaction has been open
Idle in transaction~/kbdiag session <pid>The locks it holds and whether it blocks anyone
An old or prepared transaction~/kbdiag txnThe oldest xid and who holds it, transaction age, the prepared transaction’s gid and owner
Many sessions waiting~/kbdiag waitsWhich wait event they share
Connections used up~/kbdiag sessionsThe summary at the top: a pile-up by user, database, application or client
An inactive slot~/kbdiag status on the slot’s downstream nodeWhether it answers, whether inst.upstream is streaming, and whether last_msg keeps growing

Each finding already prints the right one of these as its verify line.

Done

You have built and installed kbdiag, connected to the right instance, run status and sessions, and know what their exit codes mean.

Explore capabilities · Look up command options

3.1 - Read a real result

Real lab output of a WARN, line by line, in text and JSON.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. PIDs, counts and timings belong to this capture only. The idle-in-transaction session was created by a fault-injection script. The warning threshold was lowered to 5 seconds with --idle-in-txn-warn 5 so the example did not have to wait the default 300.

Command and output

~/kbdiag sessions --idle-in-txn-warn 5
echo EXIT_CODE=$?
sessions  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:37:04+08:00)

[WARN] session.idle_in_txn  session 1049818 has been idle in transaction for 9s
  verify: kbdiag session 1049818  # which locks it holds, whether it blocks anyone

connected: 4 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user    database  application          client
  2      esrep   esrep     internal_rwcmgr      192.168.105.10
  1      esrep   esrep     internal_rwcmgr      192.168.105.11
  1      system  test      kbdiag_inj_idle_txn  local

not idle: 2
  pid      user    database  application          client          state                xact  query  wait  sql
  1049818  system  test      kbdiag_inj_idle_txn  local           idle in transaction  11s   10s    -     select txid_current() as kbdiag_last, pg_sleep(1);
  179417   esrep   esrep     internal_rwcmgr      192.168.105.10  active               0s    0s     -     SELECT n.node_id, n.type, n.upstream_node_id, n.node_name...
EXIT_CODE=1

Line by line

  • First line: the command (sessions), the verdict (WARN) and the context: server version, role (primary), user@location (local is the socket) and when the data was collected.
  • Finding: [WARN], then a stable id (session.idle_in_txn), then the symptom: session 1049818 has been idle in transaction for 9 seconds. Scripts should rely on the id and the JSON fields; the wording of a symptom may change.
  • verify: the next command to run and why. Here: look at session 1049818 to see which locks it holds and whether it blocks anyone. A fix: line, when present, is a statement for you to review; kbdiag never runs it.
  • Data: laid out for reading. connected counts the client sessions by user, database, application and client. not idle lists the ones doing something or holding a transaction open, longest transaction first. - is null; ? would be a value this account may not see.
  • The esrep row is repmgr’s own query, caught while it ran. Idle sessions and background processes are only counted in the headings; --all lists them.
  • Exit code 1: WARN, meaning nothing is broken yet but it will be if left alone. A FAIL (the application is already affected) would be 2, UNKNOWN 3.

The same report in JSON

--json carries the same content with stable field names. This is the findings array of ~/kbdiag sessions --idle-in-txn-warn 5 --json, taken a moment later:

[
  {
    "id": "session.idle_in_txn",
    "level": "WARN",
    "symptom": "session 1049818 has been idle in transaction for 9s",
    "evidence": [
      {
        "probe_id": "session.activity",
        "fields": {
          "backend_xid": 6353,
          "pid": 1049818,
          "state": "idle in transaction",
          "state_age_s": 9.1
        }
      }
    ],
    "cause": null,
    "next": [
      {
        "kind": "verify",
        "command": "kbdiag session 1049818",
        "note": "which locks it holds, whether it blocks anyone"
      }
    ]
  }
]

The full report also has:

  • command, verdict and context.
  • data: each probe with its status, columns, rows and truncated. JSON keeps raw values (seconds, bytes, full SQL) and always carries every session, idle ones and background processes included. Here that is 12 rows, where the text lists 2.
  • redacted: the fields the account was not allowed to see.

The exit code is the same as in text mode.

What happened next

The injected session was released and a follow-up check found no test sessions left. In a real case, run the verify command and decide with the application owner whether the transaction should be committed, rolled back or the connection closed.

Investigate lock waits · Back to your first check

4 - Troubleshooting scenarios

Move from a symptom to the evidence, then confirm the outcome.

Confirm you are on the right instance before following a scenario. The examples come from fault-injection scripts on a lab cluster; you do not need to reproduce them in production.

  • Long-running SQL: find a statement that has been running for a while and what it waits on.
  • Lock waits: find who waits, follow the verify line to the blocker, and confirm the waits are gone.
  • Read a real result: a WARN in text and JSON, line by line.

4.1 - Find long-running SQL

Find a statement that has been running for a while and see what it is waiting on.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. PIDs, counts and timings belong to this capture only. A fault-injection script started select pg_sleep(3600);, a statement that only sleeps. It tests detection, not CPU or disk pressure.

kbdiag 2.0 has no slow-SQL threshold yet: a long statement is listed and sorted, but not a WARN on its own. It becomes a finding when it holds a transaction open too long (txn) or makes others wait for a lock (locks).

1. What is running?

~/kbdiag sessions
echo EXIT_CODE=$?
sessions  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:49+08:00)

connected: 4 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user    database  application            client
  2      esrep   esrep     internal_rwcmgr        192.168.105.10
  1      esrep   esrep     internal_rwcmgr        192.168.105.11
  1      system  test      kbdiag_inj_long_query  local

not idle: 1
  pid      user    database  application            client  state   xact  query  wait             sql
  1049328  system  test      kbdiag_inj_long_query  local   active  13s   13s    Timeout:PgSleep  select pg_sleep(3600);
EXIT_CODE=0
  • connected counts the client sessions by user, database, application and client; walsenders and background processes are only counted (--all lists them).
  • not idle lists the sessions doing something or holding a transaction open, longest transaction first. 1049328 has run select pg_sleep(3600); for 13 seconds. query is how long the current statement has been running; wait is what it waits on.
  • The sql column is cut at 60 characters; session <pid> shows the full text.

2. What is it waiting on?

~/kbdiag session 1049328
echo EXIT_CODE=$?
session  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:50+08:00)

session 1049328
  user         system
  database     test
  application  kbdiag_inj_long_query
  client       local
  type         client backend
  state        active  (for 14s)
  xact         14s
  query        14s
  wait         Timeout:PgSleep
  xid / xmin   - / 6353

sql
  select pg_sleep(3600);

waiting for: 0

blocking: 0

holds: 0
EXIT_CODE=0

Timeout:PgSleep says the statement is sleeping on purpose. It waits for nobody, blocks nobody and holds no lock worth showing (every transaction’s own virtualxid lock is left out). For a real statement you would see IO (reading data), Lock (waiting for another session), or no wait event at all (running on CPU).

3. Is it one statement or many?

~/kbdiag waits
echo EXIT_CODE=$?
waits  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:51+08:00)

not idle: 1
  wait             state   sessions  pids
  Timeout:PgSleep  active  1         1049328

not shown: 3 idle, 8 background
EXIT_CODE=0

waits groups the sessions that are doing something by wait event and state. One Timeout:PgSleep session means a single statement, not a pile-up; the idle sessions and idle background processes are only counted. When dozens of sessions share one wait event, that event is where to look.

4. Decide

Here the sleep is deliberate; there is nothing to tune. For a real statement, check its plan and the data it touches with the application owner. kbdiag does not cancel statements; if you decide to, use select pg_cancel_backend(<pid>); in ksql. The injected session was released afterwards and a follow-up check found none left.

Continue with lock waits

4.2 - Investigate lock waits

Find who waits, follow the verify line to the blocker, decide, and confirm the waits are gone.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. PIDs, counts and timings belong to this capture only. A fault-injection script opened a transaction that took an ACCESS EXCLUSIVE lock on a test table and then sat idle, and a second session tried to read the table.

1. Who is waiting?

~/kbdiag locks
echo EXIT_CODE=$?
locks  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:33+08:00)

[WARN] lock.waiting  session 1048829 has waited 13s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1048819
  verify: kbdiag session 1048819  # what the blocking session is doing

blockers: 1
  pid      blocks  holds
  1048819  1       public.kbdiag_inj_lock AccessExclusiveLock

waiting: 1
  pid      object                  wants            waited  blocked by
  1048829  public.kbdiag_inj_lock  AccessShareLock  13s     1048819
EXIT_CODE=1
  • Session 1048829 has waited 13 seconds for AccessShareLock on public.kbdiag_inj_lock; the direct blocker is 1048819. Waits over 10 seconds are a WARN (--lock-wait-warn changes this).
  • blockers comes first, because the first question is who is in the way. It shows 1048819 blocks one session and holds AccessExclusiveLock on the table. When one blocker holds up dozens of sessions, it is the top row.
  • waiting lists each waiting session, longest wait first. The wait is measured from the waiter’s last state change, so it can overstate the wait a little, never understate it.

2. What is the blocker doing?

Follow the verify line:

~/kbdiag session 1048819
echo EXIT_CODE=$?
session  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:34+08:00)

[WARN] lock.waiting  session 1048829 has waited 14s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1048819

session 1048819
  user         system
  database     test
  application  kbdiag_inj_lock_holder
  client       local
  type         client backend
  state        idle in transaction  (for 14s)
  xact         14s
  query        14s
  wait         -
  xid / xmin   6351 / -

last sql
  lock table kbdiag_inj_lock in access exclusive mode;

waiting for: 0

blocking: 1
  pid      object                  wants            waited
  1048829  public.kbdiag_inj_lock  AccessShareLock  14s

holds: 1
  object                  mode
  public.kbdiag_inj_lock  AccessExclusiveLock
EXIT_CODE=1
  • The blocker is idle in transaction: its last statement was lock table kbdiag_inj_lock in access exclusive mode; and it has been waiting for the client for 14 seconds with the transaction still open. Nothing is running; the lock is held because nobody committed or rolled back.
  • blocking shows who it holds up; holds shows the lock they want.
  • If waiting for is not empty, the blocker is itself waiting: run session on its blocker in turn until you reach one that is not waiting. kbdiag shows one hop at a time.
  • If a blocker is shown as 2PC, it is a prepared (two-phase) transaction with no session; find it with kbdiag txn on the primary.

3. Decide and act

kbdiag does not end sessions. Confirm with the application owner what the transaction was for. Usually the application should commit or roll back; if it cannot, end the connection yourself, for example with select pg_terminate_backend(1048819); in ksql, after checking the PID still belongs to the same user and application. Ending the blocker rolls back its transaction.

In this lab run the injection script released the holder, which ended the transaction.

4. Confirm

~/kbdiag locks
echo EXIT_CODE=$?
locks  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:36+08:00)

waiting: 0
EXIT_CODE=0

No waits, OK, exit 0. One clean sample only says the waits are gone now; if they come back, look for the application path that leaves transactions open.

Back to scenarios · locks reference

5 - User manual

Snapshot of the kbdiag README at generation time.

Command pages:status · sessions · session · locks · txn · waits · slots · space · freeze · vacuum · archive · params · repl · cluster · top-objects · table · top · progress · checkpoint · wal · seq

KingbaseES command-line diagnostics. One static binary that talks the wire protocol directly: no ksql, no interactive screens. Each command runs a single read-only look at a live instance and prints a verdict, the evidence, and the next command to run. Works on single nodes and on repmgr primary/standby clusters.

This is kbdiag 2.0, rewritten in Go; v2.0.0-alpha.1 is its first release. The shell toolkit (v1.x) is frozen; use release v1.0.0 if you need it.

Install

Build a static Linux binary (Go from go.mod), then copy it to the database host:

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=$(git describe --tags --match 'v2*' --always)" -o kbdiag ./cmd/kbdiag
scp kbdiag kingbase@db-host:~/kbdiag

Use GOARCH=arm64 for ARM hosts. The binary has no runtime dependencies.

Quick start

sudo -iu kingbase        # run as the database OS user
~/kbdiag status          # what is this instance
~/kbdiag sessions        # who is connected, who is idle in transaction
~/kbdiag locks           # who waits for a lock, and who blocks them
echo $?                  # 0 OK, 1 WARN, 2 FAIL, 3 UNKNOWN

Commands

CommandWhat it showsFlags
statusVersion, data directory, port, role; each standby (on a primary) or the WAL upstream (on a standby); uptime, connections used / usable, database sizes, disk of the data directory (local runs only). FAIL when ordinary users can no longer connect; WARN when a standby is not receiving WAL
sessionsWho holds the connections (counted by user, database, application, client), then the client sessions that are not idle, longest transaction first; WARN on long idle in transaction. JSON always carries every session--all, --limit N, --idle-in-txn-warn S
session <pid>One session: who and what it is, its full SQL, the lock it waits for and who blocks it, whom it blocks, what it holds--lock-wait-warn S, --idle-in-txn-warn S
locksWho blocks the most (and what it holds), then every lock wait, longest first, with its direct blockers; WARN on long waits--limit N, --lock-wait-warn S
txnThe oldest xid holding back vacuum and who holds it, open transactions, prepared (2PC) ones; WARN on old ones--limit N, --xact-warn S, --prepared-warn S
waitsWhat the sessions doing something wait on, grouped by wait event and state, biggest pile first; idle sessions and background processes only counted
slotsReplication slots, inactive ones and the ones keeping the most WAL first; WARN on inactive ones
spaceWhere the space goes: the filesystems holding the data directory, WAL and tablespaces (local runs only), WAL size against max_wal_size and wal_keep_segments, database and tablespace sizes. FAIL when the filesystem holding the data directory or WAL has less free space than one WAL segment; everything else is shown only
freezeHow far each database is from transaction ID wraparound, and the oldest tables of this one; WARN past autovacuum_freeze_max_age, FAIL at the stop limit where new transaction IDs are refused--limit N
vacuumThe tables with the most dead tuples and where autovacuum’s threshold is for each, what is vacuuming now; WARN when nothing will clean them (autovacuum or track_counts off, or a table past its threshold with autovacuum off for it). Primary only--limit N
archiveWhether WAL archiving works: the settings, the last success and failure, WAL waiting to be archived; WARN when the last attempt failed
paramsThe parameters someone set (not at their default) and where: file and line; WARN for each change that waits for a restart
replReplication from this node’s side: on a primary the synchronous settings and how far each standby is behind; on a standby its upstream, receive and replay. WARN when fewer synchronous standbys stream than asked for, replay is paused, or a standby receives no WAL. Lag is shown, not judged
clusterrepmgr’s view (nodes, roles, upstreams, latest events) checked against this node; WARN on two primaries, inactive nodes, a role repmgr has wrong, a standby not attached. Connects to database esrep unless -d is given
top-objectsThe largest tables (heap, indexes, TOAST) and indexes of this database. Shows only--limit N
table <name>One table: size, rows, vacuum and analyze, freeze age, access, indexes; judged with the freeze and vacuum rules. The name follows SQL rules (unquoted folds to lower case); not found is UNKNOWN
topCumulative top SQL from sys_stat_statements (since the last reset), with each statement’s share of all execution time; says so when statements are not being collected. Shows only--limit N, --by time/mean/calls/io/temp
progressHow far running VACUUM, CREATE INDEX, CLUSTER / VACUUM FULL and CHECKPOINT have got. Shows only
checkpointThe last checkpoint, timed vs requested checkpoints, who writes dirty buffers (checkpointer, bgwriter, backends), and the settings. Shows only
walWhere WAL is, how much sys_wal holds, and what keeps it: max_wal_size, wal_keep_segments, each slot, files waiting to be archived. Shows only
seqSequences of this database by how much of their range is used; FAIL when one cannot hand out another value--limit N

Defaults: idle in transaction 300 s, lock wait 10 s, transaction 300 s, prepared transaction 900 s, all WARN. --limit only trims what is shown; findings always cover every row.

Connection

FlagDefault
--host/tmp (local socket /tmp/.s.KINGBASE.54321); a host name or IP for TCP
-p, --port54321
-d, --dbnametest
-U, --usersystem
--timeout10s per query
--jsonprint the report as JSON

The password comes from PGPASSWORD or ~/.pgpass. Every connection is a read-only transaction with a lock_timeout; kbdiag never changes anything. Suggested fixes (such as ROLLBACK PREPARED) are printed, never run.

Output

locks  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-26T19:41:41+08:00)

[WARN] lock.waiting  session 803890 has waited 14s for AccessShareLock on public.kbdiag_inj_lock, blocked by 803881
  verify: kbdiag session 803881  # what the blocking session is doing

blockers: 1
  pid     blocks  holds
  803881  1       public.kbdiag_inj_lock AccessExclusiveLock

waiting: 1
  pid     object                  wants            waited  blocked by
  803890  public.kbdiag_inj_lock  AccessShareLock  14s     803881
  • First line: command, verdict, and context (version, role, user@location, collection time).
  • Findings: an id, a symptom, and a verify or fix next step.
  • Data: laid out for reading, sizes and durations in readable units; - is null, ? is hidden from this account. --json gives every probe’s raw table (bytes, seconds) with stable field names.

Exit codes

CodeMeaning
0OK
1WARN
2FAIL
3UNKNOWN: something could not be collected or seen, so kbdiag will not claim OK
64Usage error
69Cannot connect

Privileges

Run as system over the local socket for the full picture. An account without a monitoring role cannot see other sessions’ state, timings or SQL; kbdiag lists those fields under redacted and answers UNKNOWN instead of OK, unless what it can see is already WARN or FAIL. Granting sys_monitor lifts this. On a standby, prepared transactions are not_applicable (run txn on the primary); this does not change the verdict.

Requirements

  • KingbaseES V8R6 (tested on V008R006C009B0014)
  • Linux amd64 or arm64
  • repmgr is optional

5.1 - sessions: list sessions

Who holds the connections and which sessions are doing something; flag long idle-in-transaction ones.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The application sessions named kbdiag_inj_* were created by fault-injection scripts. PIDs, counts and timings belong to this capture only.

Usage

kbdiag sessions [--all] [--limit N] [--idle-in-txn-warn SECONDS] [--json]
FlagEffect
--allList every session, including idle ones and background processes
--limit NShow at most N rows, default 50; 0 shows all
--idle-in-txn-warn SECONDSWARN when a session is idle in transaction longer than this, default 300
--jsonPrint the report as JSON

Connection flags --host, -p, -d, -U and --timeout are global. Defaults: local socket in /tmp, port 54321, database test, user system. The password comes from PGPASSWORD or ~/.pgpass. The connection runs read-only transactions and sets lock_timeout.

--all and --limit only change what is displayed. The summary and the findings always cover every session, so a session that is not shown can still raise a WARN.

Default output

Several injected sessions are open: a table lock held idle in transaction and a reader waiting for it, a second idle-in-transaction session, a session waiting on a prepared transaction, and a pg_sleep(3600).

~/kbdiag sessions
echo EXIT_CODE=$?
sessions  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:17+08:00)

connected: 8 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user    database  application                 client
  2      esrep   esrep     internal_rwcmgr             192.168.105.10
  1      esrep   esrep     internal_rwcmgr             192.168.105.11
  1      system  test      kbdiag_inj_idle_txn         local
  1      system  test      kbdiag_inj_lock_holder      local
  1      system  test      kbdiag_inj_lock_waiter      local
  1      system  test      kbdiag_inj_long_query       local
  1      system  test      kbdiag_inj_prepared_waiter  local

not idle: 5
  pid      user    database  application                 client  state                xact  query  wait             sql
  1045715  system  test      kbdiag_inj_lock_holder      local   idle in transaction  30s   30s    -                lock table kbdiag_inj_lock in access exclusive mode;
  1045724  system  test      kbdiag_inj_lock_waiter      local   active               30s   30s    Lock:relation    select count(*) from kbdiag_inj_lock;
  1045809  system  test      kbdiag_inj_idle_txn         local   idle in transaction  28s   27s    -                select txid_current() as kbdiag_last, pg_sleep(1);
  1046007  system  test      kbdiag_inj_prepared_waiter  local   active               25s   25s    Lock:relation    lock table kbdiag_inj_2pc in access exclusive mode;
  1046088  system  test      kbdiag_inj_long_query       local   active               24s   24s    Timeout:PgSleep  select pg_sleep(3600);
EXIT_CODE=0
  • connected: answers “who holds the connections”. Client sessions are counted by user, database, application and client, leaving out kbdiag’s own connection. Walsenders and background processes are only counted in the heading. local is the Unix socket.
  • not idle: lists the client sessions that are doing something or hold a transaction open: active, idle in transaction and the like. Idle sessions and background processes are not listed; --all lists them.
  • Rows are sorted by transaction age, longest first. Sessions without a transaction come last, then by PID.
  • xact is the transaction age and query the age of the current (or last) statement. wait is the wait event as type:event. sql is cut to 60 characters; session <pid> shows it in full. - means null.
  • The two idle-in-transaction sessions have been so for about 30 seconds, below the default 300, so the verdict is OK.

A WARN

Only the idle-in-transaction session is left, and the threshold is lowered to 5 seconds so the example does not have to wait 300:

~/kbdiag sessions --idle-in-txn-warn 5
echo EXIT_CODE=$?
sessions  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:37:04+08:00)

[WARN] session.idle_in_txn  session 1049818 has been idle in transaction for 9s
  verify: kbdiag session 1049818  # which locks it holds, whether it blocks anyone

connected: 4 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user    database  application          client
  2      esrep   esrep     internal_rwcmgr      192.168.105.10
  1      esrep   esrep     internal_rwcmgr      192.168.105.11
  1      system  test      kbdiag_inj_idle_txn  local

not idle: 2
  pid      user    database  application          client          state                xact  query  wait  sql
  1049818  system  test      kbdiag_inj_idle_txn  local           idle in transaction  11s   10s    -     select txid_current() as kbdiag_last, pg_sleep(1);
  179417   esrep   esrep     internal_rwcmgr      192.168.105.10  active               0s    0s     -     SELECT n.node_id, n.type, n.upstream_node_id, n.node_name...
EXIT_CODE=1
  • One finding per session over the threshold. The verify line gives the next command to run.
  • The esrep row is repmgr’s own query, caught while it ran.
  • Exit code 1 means at least one WARN.

Idle in transaction for 5 minutes is a fault whatever the application: a pool that leaked a connection, or a missing commit. 300 seconds filters out noise; it is not a capacity line. Raise it if DBAs routinely hold transactions open by hand. txn reports the same session as a long transaction at the same default. The two findings answer different questions (“it sits idle” and “its transaction is long”), so both stay.

Who holds the connections

When status reports that ordinary users can no longer connect, its verify line points here. A fault-injection script filled every connection ordinary users may open:

~/kbdiag sessions
echo EXIT_CODE=$?
sessions  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:38:17+08:00)

connected: 96 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user       database  application      client
  93     kbdiag_ro  test      kbdiag_inj_conn  127.0.0.1
  2      esrep      esrep     internal_rwcmgr  192.168.105.10
  1      esrep      esrep     internal_rwcmgr  192.168.105.11

not idle: 0
EXIT_CODE=0

The summary shows the pile-up at once: 93 idle sessions of kbdiag_ro from 127.0.0.1, application kbdiag_inj_conn. They are idle, so not idle is empty.

Fewer rows

~/kbdiag sessions --limit 2
echo EXIT_CODE=$?
sessions  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:20+08:00)

connected: 8 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user    database  application                 client
  2      esrep   esrep     internal_rwcmgr             192.168.105.10
  1      esrep   esrep     internal_rwcmgr             192.168.105.11
  1      system  test      kbdiag_inj_idle_txn         local
  1      system  test      kbdiag_inj_lock_holder      local
  1      system  test      kbdiag_inj_lock_waiter      local
  1      system  test      kbdiag_inj_long_query       local
  1      system  test      kbdiag_inj_prepared_waiter  local

not idle: 5
  pid      user    database  application             client  state                xact  query  wait           sql
  1045715  system  test      kbdiag_inj_lock_holder  local   idle in transaction  33s   33s    -              lock table kbdiag_inj_lock in access exclusive mode;
  1045724  system  test      kbdiag_inj_lock_waiter  local   active               33s   33s    Lock:relation  select count(*) from kbdiag_inj_lock;
... 3 more rows not shown (use --limit 0 to show all)
EXIT_CODE=0

--limit cuts the not idle list (and the rows in --json); the last line says how many are not shown. The summary and the findings still cover every session.

Every session

~/kbdiag sessions --all
echo EXIT_CODE=$?
sessions  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:34:46+08:00)

connected: 3 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user   database  application      client
  2      esrep  esrep     internal_rwcmgr  192.168.105.10
  1      esrep  esrep     internal_rwcmgr  192.168.105.11

all: 11
  pid     user    database  application          client          type                          state   xact  query  wait                    sql
  3271    -       -         check pointer        -               checkpointer                  -       -     -      -                       -
  3272    -       -         background flush     -               background writer             -       -     -      -                       -
  3273    -       -         wal flush            -               walwriter                     -       -     -      -                       -
  3274    -       -         auto vacuum          -               autovacuum launcher           -       -     -      -                       -
  3279    system  kingbase  ksh writer           -               ksh writer                    idle    -     2s     -                       select pg_catalog.metric_update_timer();
  3280    system  -         sys_ksh collector    -               ksh collector                 idle    -     -      -                       -
  3281    system  -         logical replication  -               logical replication launcher  -       -     -      -                       -
  3294    esrep   esrep     internal_rwcmgr      192.168.105.10  client backend                idle    -     2s     -                       SELECT n.node_id as nodeId, n.type as nodeType, n.upstrea...
  179417  esrep   esrep     internal_rwcmgr      192.168.105.10  client backend                idle    -     2s     -                       SELECT pg_catalog.pg_is_in_recovery()
  759699  esrep   esrep     internal_rwcmgr      192.168.105.11  client backend                idle    -     2s     -                       SELECT state,sync_state FROM pg_stat_replication where ap...
  903372  esrep   -         node2                192.168.105.11  walsender                     active  -     -      Activity:WalSenderMain  -
EXIT_CODE=0

--all lists idle sessions and background processes too, and adds a type column (backend_type). The walsender is the replication connection to the standby.

Insufficient privilege

Connect as kbdiag_ro, an account without a monitoring role, while the injected sessions are still there:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro sessions
echo EXIT_CODE=$?
sessions  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-09-27T13:35:25+08:00)

connected: 1 walsender, 15 hidden
  count  user    database  application                 client
  3      esrep   esrep     internal_rwcmgr             ?
  1      -       -         auto vacuum                 ?
  1      -       -         background flush            ?
  1      -       -         check pointer               ?
  1      -       -         wal flush                   ?
  1      system  -         logical replication         ?
  1      system  -         sys_ksh collector           ?
  1      system  kingbase  -                           ?
  1      system  test      kbdiag_inj_idle_txn         ?
  1      system  test      kbdiag_inj_lock_holder      ?
  1      system  test      kbdiag_inj_lock_waiter      ?
  1      system  test      kbdiag_inj_long_query       ?
  1      system  test      kbdiag_inj_prepared_waiter  ?

not idle: 0 visible, 15 hidden
redacted: 15 rows of session.activity hide state, backend_type, client_addr, ages, wait, query (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • This account cannot see the state, type, client address, times, wait event or SQL of other users’ sessions. It cannot tell whether a session is working, idle or a background process, so none is called idle: all 15 are hidden, and they are still counted in the summary by user, database and application.
  • ? is a value this account may not see; - is null.
  • The sessions cannot be judged, so the verdict is UNKNOWN with exit code 3, not OK. The redacted line names the hidden columns and the fix: grant sys_monitor.
  • A session that turns off track_activities for itself (SET or ALTER ROLE ... SET) shows the state disabled. It is still listed, but its times show ?: the server keeps old values. It also makes the verdict UNKNOWN, with the reason track_activities_off.

JSON

--json always carries every session, idle ones and background processes included, with raw values: times in seconds and the full SQL. See Read a real result for its shape.

Exit codes

CodeMeaning
0OK
1WARN: a session idle in transaction too long
3UNKNOWN: some sessions not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.2 - session: one session

One session: its full SQL, what it waits for, whom it blocks and which locks it holds.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The sessions in the examples were created by fault-injection scripts: 1045715 holds an exclusive lock on table kbdiag_inj_lock idle in transaction, 1045724 waits for it, and 1045809 is a second session idle in transaction. PIDs, counts and timings belong to this capture only.

Usage

kbdiag session <pid> [--lock-wait-warn SECONDS] [--idle-in-txn-warn SECONDS] [--json]
OptionEffect
<pid>PID of the session to show; required
--lock-wait-warn SECONDSWARN when waiting for a lock longer than this; default 10
--idle-in-txn-warn SECONDSWARN when idle in transaction longer than this; default 300
--jsonPrint JSON

Connection options are the same as for sessions. The thresholds and findings are the same as those of sessions and locks.

A session waiting for a lock

~/kbdiag session 1045724
echo EXIT_CODE=$?
session  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:22+08:00)

[WARN] lock.waiting  session 1045724 has waited 35s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1045715
  verify: kbdiag session 1045715  # what the blocking session is doing

session 1045724
  user         system
  database     test
  application  kbdiag_inj_lock_waiter
  client       local
  type         client backend
  state        active  (for 35s)
  xact         35s
  query        35s
  wait         Lock:relation
  xid / xmin   - / 6343

sql
  select count(*) from kbdiag_inj_lock;

waiting for: 1
  object                  wants            waited  blocked by
  public.kbdiag_inj_lock  AccessShareLock  35s     1045715

blocking: 0

holds: 0
EXIT_CODE=1
  • The block at the top says who the session is (user, database, application, client, type) and what it does: its state and how long it has been in it, the transaction and statement ages, the wait event, and its transaction id and snapshot xmin.
  • sql is the statement in full, with its line breaks. This is the only command that shows the whole SQL. For an idle session the heading reads last sql, since that statement has finished.
  • waiting for is the lock it wants, how long it has waited and who blocks it directly.
  • It has waited 35 seconds, over the default 10, so there is a lock.waiting WARN and the exit code is 1. The verify line points at the blocker.
  • waited is measured from the session’s last state change, so it can overstate the wait a little, never understate it.

The blocking session

~/kbdiag session 1045715
echo EXIT_CODE=$?
session  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:21+08:00)

[WARN] lock.waiting  session 1045724 has waited 34s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1045715

session 1045715
  user         system
  database     test
  application  kbdiag_inj_lock_holder
  client       local
  type         client backend
  state        idle in transaction  (for 34s)
  xact         34s
  query        34s
  wait         -
  xid / xmin   6343 / -

last sql
  lock table kbdiag_inj_lock in access exclusive mode;

waiting for: 0

blocking: 1
  pid      object                  wants            waited
  1045724  public.kbdiag_inj_lock  AccessShareLock  34s

holds: 1
  object                  mode
  public.kbdiag_inj_lock  AccessExclusiveLock
EXIT_CODE=1
  • blocking lists the sessions waiting for locks this session holds. holds lists its locks.
  • Every transaction holds its own virtualxid and transactionid locks; they are left out of holds unless someone waits for a lock of that type. The xid is in the block at the top.
  • A row lock is labelled with its type, for example public.t (tuple), so it is not read as a table lock.
  • The WARN is the waiter’s lock.waiting: it says this session has been blocking another for 34 seconds, which is this session’s problem. It has no verify line, since it would point back here.
  • The session has been idle in transaction for 34 seconds: it took the lock and never committed. Its own session.idle_in_txn would come at 300 seconds.

Idle in transaction

With the threshold lowered to 10 seconds:

~/kbdiag session 1045809 --idle-in-txn-warn 10
echo EXIT_CODE=$?
session  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:23+08:00)

[WARN] session.idle_in_txn  session 1045809 has been idle in transaction for 32s

session 1045809
  user         system
  database     test
  application  kbdiag_inj_idle_txn
  client       local
  type         client backend
  state        idle in transaction  (for 33s)
  xact         35s
  query        34s
  wait         -
  xid / xmin   6344 / -

last sql
  select txid_current() as kbdiag_last, pg_sleep(1);

waiting for: 0

blocking: 0

holds: 0
EXIT_CODE=1

The session has a transaction id but holds no lock others want, so holds is empty. What it holds back is the vacuum horizon; see txn.

Insufficient privilege

Connect as kbdiag_ro, which has no monitoring role, and look at the blocker:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro session 1045715
echo EXIT_CODE=$?
session  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-09-27T13:35:28+08:00)

session 1045715
  user         system
  database     test
  application  kbdiag_inj_lock_holder
  client       ?
  type         ?
  state        ?
  xact         ?
  query        ?
  wait         ?
  xid / xmin   6343 / -

sql
  ?

waiting for: 0

blocking: 1
  pid      object                  wants            waited
  1045724  public.kbdiag_inj_lock  AccessShareLock  ?

holds: 1
  object                  mode
  public.kbdiag_inj_lock  AccessExclusiveLock
redacted: 1 row of session.activity hides state, backend_type, client_addr, ages, wait, query (insufficient_privilege; grant sys_monitor)
redacted: 1 row of lock.list hides wait (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • User, database and application are visible, and so are the transaction id and xmin. State, times, client, type, wait and SQL show ?.
  • Locks and who blocks whom are visible; how long the other session has waited is not.
  • The session cannot be judged, so the verdict is UNKNOWN with exit code 3. Grant sys_monitor to see everything.

No such session

~/kbdiag session 999999
echo EXIT_CODE=$?
kbdiag: no session with pid 999999 (it may have ended)
session  UNKNOWN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:34:46+08:00)

session 999999: not found (it may have ended)
EXIT_CODE=3

When the PID is not found (it may have ended), a note goes to standard error, the verdict is UNKNOWN and the exit code 3. Omitting the PID is a usage error, exit code 64.

JSON

--json carries the activity row and the lock rows the text is built from, with raw values: times in seconds and every lock row, including virtualxid. The lock.waiting finding of the waiter above, with the fields scripts can use:

{
  "id": "lock.waiting",
  "level": "WARN",
  "symptom": "session 1045724 has waited 37s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1045715",
  "evidence": [
    {
      "probe_id": "lock.list",
      "fields": {
        "blocker_pids": [
          1045715
        ],
        "lock_mode": "AccessShareLock",
        "relation": "public.kbdiag_inj_lock",
        "wait_s": 37.3,
        "waiter_pid": 1045724
      }
    }
  ],
  "cause": null,
  "next": [
    {
      "kind": "verify",
      "command": "kbdiag session 1045715",
      "note": "what the blocking session is doing"
    }
  ]
}

Exit codes

CodeMeaning
0OK
1WARN: a lock wait or idle in transaction over its threshold
3UNKNOWN: no such session, or data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.3 - locks: lock waits

Who blocks whom: the blockers first, then every session waiting for a lock, how long, and why.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The lock waits were created by fault-injection scripts. On the primary, 1045715 holds an exclusive lock on table kbdiag_inj_lock idle in transaction and 1045724 waits for it. A prepared (two-phase) transaction holds a lock on kbdiag_inj_2pc, and 1046007 waits for that. PIDs, counts and timings belong to this capture only.

Usage

kbdiag locks [--limit N] [--lock-wait-warn SECONDS] [--json]
OptionEffect
--limit NShow at most N waiting sessions; default 50, 0 for all
--lock-wait-warn SECONDSWARN when waiting for a lock longer than this; default 10
--jsonPrint JSON

Connection options are the same as for sessions. --limit only cuts the waiting list; the findings always cover every wait.

Sessions waiting for locks

~/kbdiag locks
echo EXIT_CODE=$?
locks  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:17+08:00)

[WARN] lock.waiting  session 1045724 has waited 30s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1045715
  verify: kbdiag session 1045715  # what the blocking session is doing

[WARN] lock.waiting  session 1046007 has waited 25s for AccessExclusiveLock on public.kbdiag_inj_2pc, blocked by an uncommitted two-phase transaction
  verify: kbdiag txn  # the blocker is an uncommitted two-phase transaction: its gid and how long it has been pending

blockers: 2
  pid      blocks  holds
  2PC      1       public.kbdiag_inj_2pc RowExclusiveLock
  1045715  1       public.kbdiag_inj_lock AccessExclusiveLock

waiting: 2
  pid      object                  wants                waited  blocked by
  1045724  public.kbdiag_inj_lock  AccessShareLock      30s     1045715
  1046007  public.kbdiag_inj_2pc   AccessExclusiveLock  25s     2PC
EXIT_CODE=1
  • blockers comes first, because the first question in an incident is who is blocking. One blocker often holds up dozens of sessions, so they are sorted by how many sessions they block. holds is what the blocker holds on the objects its waiters want.
  • A prepared transaction belongs to no session, so it is shown as 2PC. Its finding says so and points at kbdiag txn, which gives its gid and age.
  • A blocker that is itself waiting is marked (queued ahead for ...): the server counts a conflicting session queued earlier as a blocker too.
  • waiting lists every session waiting for a lock, longest wait first. blocked by names the direct blockers only. For a longer chain, run session on the blocker in turn.
  • Each waiting session over --lock-wait-warn gets one lock.waiting finding. Shorter waits are listed but not flagged.
  • waited is measured from the waiter’s last state change: V8R6 has no lock-wait start time. It can overstate the wait a little, never understate it.

A 10-second lock wait is already an incident for OLTP but can be normal for a batch job, so it is a WARN, not a FAIL. 10 seconds filters out passing row-lock contention. Batch databases may want it higher.

With no waits:

~/kbdiag locks
echo EXIT_CODE=$?
locks  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:34:43+08:00)

waiting: 0
EXIT_CODE=0

On a standby

A session-level advisory lock, taken on the standby:

~/kbdiag locks
echo EXIT_CODE=$?
locks  WARN  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:37:19+08:00)

[WARN] lock.waiting  session 599825 has waited 14s for advisory lock, blocked by 599816
  verify: kbdiag session 599816  # what the blocking session is doing

blockers: 1
  pid     blocks  holds
  599816  1       advisory ExclusiveLock

waiting: 1
  pid     object    wants          waited  blocked by
  599825  advisory  ExclusiveLock  14s     599816
EXIT_CODE=1

A lock with no table, such as an advisory lock, shows its lock type as the object.

Insufficient privilege

Connect as kbdiag_ro, which has no monitoring role, while the waits on the primary are still there:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro locks
echo EXIT_CODE=$?
locks  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-09-27T13:35:26+08:00)

blockers: 2
  pid      blocks  holds
  2PC      1       public.kbdiag_inj_2pc RowExclusiveLock
  1045715  1       public.kbdiag_inj_lock AccessExclusiveLock

waiting: 2
  pid      object                  wants                waited  blocked by
  1045724  public.kbdiag_inj_lock  AccessShareLock      ?       1045715
  1046007  public.kbdiag_inj_2pc   AccessExclusiveLock  ?       2PC
redacted: 2 rows of lock.list hide wait (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • The locks and who blocks whom are visible. This account cannot see other sessions’ timestamps, so the waits show ? and the threshold cannot be checked. The verdict is UNKNOWN, exit code 3.
  • Grant sys_monitor to see everything.

JSON

--json lists the lock rows of the waiting sessions, plus the blockers’ locks on the same objects: pid, locktype, relation, mode, granted, wait_s and blocked_by. blocked_by keeps the server’s raw list: a prepared transaction appears as 0.

Limits

  • Parallel query workers have their own PIDs and lock rows, so one waiting parallel query may count as several blocked sessions.
  • Several advisory locks of one blocker are listed together in its holds, since only the lock type is compared.

Exit codes

CodeMeaning
0OK
1WARN: a session waited for a lock too long
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.4 - txn: transactions

Who holds back the vacuum horizon: open transactions, prepared (two-phase) ones, and the oldest of them.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The transactions in the examples were created by fault-injection scripts: two sessions idle in transaction (one holding a table lock), sessions waiting for locks, a pg_sleep(3600), and kbdiag_inj_2pc, a prepared transaction that was neither committed nor rolled back. PIDs, counts and timings belong to this capture only.

Usage

kbdiag txn [--limit N] [--xact-warn SECONDS] [--prepared-warn SECONDS] [--json]
OptionEffect
--limit NShow at most N transactions; default 50, 0 for all
--xact-warn SECONDSWARN when a transaction is older than this; default 300
--prepared-warn SECONDSWARN when a prepared transaction is older than this; default 900
--jsonPrint JSON

Connection options are the same as for sessions. --limit only affects what is shown; the findings always cover every transaction.

Default output

~/kbdiag txn
echo EXIT_CODE=$?
txn  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:18+08:00)

oldest xid: 6343  (1045715 xid, 1045724 xmin, 1046007 xmin, 1046088 xmin)

open transactions: 5
  pid      user    database  application                 state                xact  xid   xmin  sql
  1045715  system  test      kbdiag_inj_lock_holder      idle in transaction  31s   6343  -     lock table kbdiag_inj_lock in access exclusive mode;
  1045724  system  test      kbdiag_inj_lock_waiter      active               30s   -     6343  select count(*) from kbdiag_inj_lock;
  1045809  system  test      kbdiag_inj_idle_txn         idle in transaction  29s   6344  -     select txid_current() as kbdiag_last, pg_sleep(1);
  1046007  system  test      kbdiag_inj_prepared_waiter  active               25s   6347  6343  lock table kbdiag_inj_2pc in access exclusive mode;
  1046088  system  test      kbdiag_inj_long_query       active               25s   -     6343  select pg_sleep(3600);

prepared: 1
  gid             owner   database  age  xid
  kbdiag_inj_2pc  system  test      26s  6346
EXIT_CODE=0
  • oldest xid is the oldest transaction id any session or prepared transaction holds, and who holds it. Here 1045715 has transaction id 6343, and three others have snapshots (xmin) taken while 6343 was running. VACUUM cannot remove row versions newer than this, so this line answers “who holds back the vacuum horizon”. Ids are compared modulo 2^32, as the server does.
  • open transactions lists sessions inside a transaction, meaning with a transaction start time, a transaction id or a snapshot xmin. The oldest transaction comes first. xid is assigned at the first write; a read-only transaction has only xmin.
  • prepared lists every prepared transaction: gid, owner, database, age and xid. They belong to no session, so sessions cannot show them.
  • Nothing is past its default threshold, so the verdict is OK.

WARN

With both thresholds lowered to 10 seconds:

~/kbdiag txn --xact-warn 10 --prepared-warn 10
echo EXIT_CODE=$?
txn  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:21+08:00)

[WARN] txn.long  session 1045715 has had a transaction open for 34s, now idle in transaction
  verify: kbdiag session 1045715  # what it is running, which locks it holds, whether it blocks anyone

[WARN] txn.long  session 1045724 has had a transaction open for 34s, now active
  verify: kbdiag session 1045724  # what it is running, which locks it holds, whether it blocks anyone

[WARN] txn.long  session 1045809 has had a transaction open for 32s, now idle in transaction
  verify: kbdiag session 1045809  # what it is running, which locks it holds, whether it blocks anyone

[WARN] txn.long  session 1046007 has had a transaction open for 28s, now active
  verify: kbdiag session 1046007  # what it is running, which locks it holds, whether it blocks anyone

[WARN] txn.long  session 1046088 has had a transaction open for 28s, now active
  verify: kbdiag session 1046088  # what it is running, which locks it holds, whether it blocks anyone

[WARN] txn.prepared  two-phase transaction kbdiag_inj_2pc prepared 29s ago and not finished, holding back the vacuum horizon
  fix: ROLLBACK PREPARED 'kbdiag_inj_2pc'  # check with the application whether to commit (COMMIT PREPARED) or roll back; run it connected to database test, outside a transaction block

oldest xid: 6343  (1045715 xid, 1045724 xmin, 1046007 xmin, 1046088 xmin)

open transactions: 5
  pid      user    database  application                 state                xact  xid   xmin  sql
  1045715  system  test      kbdiag_inj_lock_holder      idle in transaction  34s   6343  -     lock table kbdiag_inj_lock in access exclusive mode;
  1045724  system  test      kbdiag_inj_lock_waiter      active               34s   -     6343  select count(*) from kbdiag_inj_lock;
  1045809  system  test      kbdiag_inj_idle_txn         idle in transaction  32s   6344  -     select txid_current() as kbdiag_last, pg_sleep(1);
  1046007  system  test      kbdiag_inj_prepared_waiter  active               28s   6347  6343  lock table kbdiag_inj_2pc in access exclusive mode;
  1046088  system  test      kbdiag_inj_long_query       active               28s   -     6343  select pg_sleep(3600);

prepared: 1
  gid             owner   database  age  xid
  kbdiag_inj_2pc  system  test      29s  6346
EXIT_CODE=1
  • txn.long: one per transaction older than --xact-warn. The verify line leads to the session.
  • txn.prepared: a prepared transaction older than --prepared-warn. It keeps its locks and holds back the vacuum horizon until someone commits or rolls it back. The fix line gives the statement; kbdiag only prints it. Its note says to confirm with the application whether to commit (COMMIT PREPARED) or roll back, and to run it connected to the transaction’s database, outside a transaction block.
  • If a gid contains control characters, the terminal shows it escaped and a copied statement would not match. In that case there is no fix line; the verify line says to take the raw gid from --json.
  • Both are WARN, never FAIL. Their harm, table bloat and locks held for a long time, is still to come. The sessions they block now are reported by locks.
  • 300 and 900 seconds have no server-side counterpart. 300 can catch a normal batch job, so raise them on batch databases.
  • At default thresholds a session idle in transaction for over 300 seconds is also reported by sessions as session.idle_in_txn. The two answer different questions.

On a standby

~/kbdiag txn
echo EXIT_CODE=$?
txn  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:37:20+08:00)

oldest xid: 6354  (599825 xmin)

open transactions: 1
  pid     user    database  application             state   xact  xid  xmin  sql
  599825  system  test      kbdiag_inj_lock_waiter  active  14s   -    6354  select pg_advisory_lock(424242);

txn.prepared: not_applicable  (a standby cannot see the primary's two-phase transactions: run kbdiag txn on the primary)
EXIT_CODE=0

A standby cannot see the primary’s prepared transactions, so txn.prepared is not_applicable. That does not mean “none”, and it does not affect the verdict. Run txn on the primary.

Insufficient privilege

Connect as kbdiag_ro, which has no monitoring role:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro txn
echo EXIT_CODE=$?
txn  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-09-27T13:35:27+08:00)

oldest xid: 6343  (1045715 xid, 1045724 xmin, 1046007 xmin, 1046088 xmin)

open transactions: 5, 10 sessions hidden
  pid      user    database  application                 state  xact  xid   xmin  sql
  1045715  system  test      kbdiag_inj_lock_holder      ?      ?     6343  -     ?
  1045724  system  test      kbdiag_inj_lock_waiter      ?      ?     -     6343  ?
  1045809  system  test      kbdiag_inj_idle_txn         ?      ?     6344  -     ?
  1046007  system  test      kbdiag_inj_prepared_waiter  ?      ?     6347  6343  ?
  1046088  system  test      kbdiag_inj_long_query       ?      ?     -     6343  ?

prepared: 1
  gid             owner   database  age  xid
  kbdiag_inj_2pc  system  test      35s  6346
redacted: 15 rows of session.activity hide state, backend_type, client_addr, ages, wait, query (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • KingbaseES shows other sessions’ transaction id and xmin to any account, so oldest xid and the open transactions are still found. Their state, age and SQL show ?.
  • Hidden sessions with neither an xid nor an xmin are only counted (10 sessions hidden). They are most likely idle, and they are not called transactions.
  • The verdict is UNKNOWN, exit code 3. Grant sys_monitor to see everything.
  • When session activity or the prepared transactions could not be collected, oldest xid says an older one may exist, or shows unknown if nothing was found.

Exit codes

CodeMeaning
0OK
1WARN: a long transaction or a long-pending prepared transaction
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.5 - waits: wait events

What the working sessions are waiting on right now, biggest pile first.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The sessions in the examples were created by fault-injection scripts: two sessions idle in transaction, two waiting for table locks, and a pg_sleep(3600). PIDs, counts and timings belong to this capture only.

Usage

kbdiag waits [--json]

No options of its own. Connection options are the same as for sessions.

Default output

~/kbdiag waits
echo EXIT_CODE=$?
waits  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:35:18+08:00)

not idle: 5
  wait               state                sessions  pids
  Lock:relation      active               2         1045724 1046007
  Client:ClientRead  idle in transaction  2         1045715 1045809
  Timeout:PgSleep    active               1         1046088

not shown: 3 idle, 8 background
EXIT_CODE=0
  • not idle groups the sessions that are doing something by wait event and state. sessions counts them and pids lists them. The biggest group comes first, since a pile-up is what to look for; on a tie active comes first.
  • Lock:relation: two sessions wait for table locks; who blocks them and for how long is in locks.
  • Client:ClientRead with idle in transaction: the sessions wait for their client to send the next statement while holding a transaction open.
  • Timeout:PgSleep is the injected pg_sleep. An active session with no wait event shows (running): on CPU, or in code without a wait event.
  • pids lists up to 10 PIDs, then ... (+N). --json has them all.
  • not shown counts what is left out. idle sessions do not answer “where is it stuck”. Nor do background processes idling in their main loop (any Activity wait, such as a walsender with nothing to send or the checkpointer between checkpoints). A background process stuck on a real wait, for example the checkpointer on IO:DataFileSync, is listed with the state (background).

There are no thresholds and no options. Ten sessions waiting on IO can be an incident on one database and routine on another, so waits only reports. A lock wait that is too long is judged by locks.

A quiet primary:

~/kbdiag waits
echo EXIT_CODE=$?
waits  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:34:44+08:00)

not idle: 0

not shown: 3 idle, 8 background
EXIT_CODE=0

On a busy primary a walsender catching up may appear with a wait such as IO:WALRead; that is normal.

On a standby

~/kbdiag waits
echo EXIT_CODE=$?
waits  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:37:21+08:00)

not idle: 1
  wait           state   sessions  pids
  Lock:advisory  active  1         599825

not shown: 3 idle, 4 background
EXIT_CODE=0

Insufficient privilege

Connect as kbdiag_ro, which has no monitoring role:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro waits
echo EXIT_CODE=$?
waits  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-09-27T13:35:27+08:00)

not idle: 0

not shown: 1 background, 15 hidden (state unknown)
redacted: 15 rows of wait.summary hide wait, state (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • Other users’ sessions have no visible wait event or state. They may be idle or not, so they are counted as hidden (state unknown), not as idle. Sessions that turned off track_activities are counted as untracked (state unknown) for the same reason.
  • With hidden sessions kbdiag cannot claim nothing is waiting, so the verdict is UNKNOWN, exit code 3. Grant sys_monitor to see everything.

JSON

--json has every group, idle and background ones included, with the full PID lists: wait_event_type, wait_event, state, sessions and pids.

Exit codes

CodeMeaning
0OK
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.6 - status: instance overview

What this instance is and whether its basics hold: role, replication, connections, database sizes, disk.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The FAIL example was created by a fault-injection script that fills every connection ordinary users may open. Values belong to this capture only.

Usage

kbdiag status [--json]

status has no options of its own. Connection options are the same as for sessions.

Only two things are judged:

  • FAIL when every connection ordinary users may open is taken (max_connections less superuser_reserved_connections). At that point the application can no longer connect.
  • WARN on a standby that is not receiving WAL, meaning it has no WAL receiver or its status is not streaming. Queries still work, but if the primary fails now there is no up-to-date standby to take over.

There is no “almost full” warning. How many connections is too many depends on the application, so status shows the count and leaves that call to you.

On the primary

~/kbdiag status
echo EXIT_CODE=$?
status  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:34:42+08:00)

inst.info
  version         V008R006C009B0014
  data_directory  /home/kingbase/cluster/install/kingbase/data
  port            54321
  start_time      2026-09-20 22:19:13  (up 6d 15h)
  connections     5 / 97  (max_connections 100 - superuser_reserved 3)

inst.downstreams: 1
  name   address         state      sync
  node2  192.168.105.11  streaming  quorum

inst.upstream: not_applicable  (primary)

inst.databases: 5, total 382 MB
  test      325 MB
  esrep      15 MB
  mydb       14 MB
  kingbase   14 MB
  security   14 MB

inst.disk  (filesystem of data_directory)
  used   14 GB / 199 GB  (7%)
  free  185 GB
EXIT_CODE=0
  • The role in the first line (primary / standby) comes from sys_is_in_recovery().
  • inst.info: connections counts only backends connected to a database, not background processes. It compares directly with the 97 connections ordinary users may open.
  • inst.downstreams: one row per standby this instance sends WAL to, from sys_stat_replication. sync is shown as the server reports it. With repmgr it reads quorum here, not sync / async.
  • inst.upstream only applies to a standby.
  • inst.databases: non-template databases, largest first. Sizes use 1024-based units, as pg_size_pretty does.
  • inst.disk: the filesystem holding data_directory, as df reports it. Used plus free is less than the total by the blocks reserved for root. It is shown, not judged.

On the standby

~/kbdiag status
echo EXIT_CODE=$?
status  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:37:22+08:00)

inst.info
  version         V008R006C009B0014
  data_directory  /home/kingbase/cluster/install/kingbase/data
  port            54321
  start_time      2026-09-23 15:44:58  (up 3d 21h)
  connections     5 / 97  (max_connections 100 - superuser_reserved 3)

inst.upstream
  status    streaming
  upstream  192.168.105.10:54321
  slot      repmgr_slot_2
  last_msg  11s ago

inst.downstreams: 0

inst.databases: 5, total 382 MB
  test      325 MB
  esrep      15 MB
  kingbase   14 MB
  mydb       14 MB
  security   14 MB

inst.disk  (filesystem of data_directory)
  used   12 GB / 199 GB  (6%)
  free  187 GB
EXIT_CODE=0
  • On a standby the upstream comes first. It comes from sys_stat_wal_receiver: where the standby gets WAL from, through which slot, and when the last message arrived.
  • last_msg is shown, not judged. A quiet primary only sends a message every wal_receiver_status_interval (10 seconds by default), so a few seconds is normal.
  • A paused WAL receiver (for example one stopped with SIGSTOP) keeps the status streaming, so status does not report it. If last_msg keeps growing, check the standby’s WAL receiver process yourself. The slots page shows a real capture of this.

All connections taken

~/kbdiag status
echo EXIT_CODE=$?
status  FAIL  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:38:16+08:00)

[FAIL] inst.connections  98 connections in use, reaching the 97 ordinary users may open (max_connections 100 minus 3 reserved for superusers): ordinary users can no longer connect
  verify: kbdiag sessions  # who holds the connections: the summary at the top counts them by user, database, application and client

inst.info
  version         V008R006C009B0014
  data_directory  /home/kingbase/cluster/install/kingbase/data
  port            54321
  start_time      2026-09-20 22:19:13  (up 6d 15h)
  connections     98 / 97  (max_connections 100 - superuser_reserved 3)

inst.downstreams: 1
  name   address         state      sync
  node2  192.168.105.11  streaming  quorum

inst.upstream: not_applicable  (primary)

inst.databases: 5, total 382 MB
  test      325 MB
  esrep      15 MB
  mydb       14 MB
  kingbase   14 MB
  security   14 MB

inst.disk  (filesystem of data_directory)
  used   14 GB / 199 GB  (7%)
  free  185 GB
EXIT_CODE=2
  • 98 is above 97 because superusers still get in through the reserve, including kbdiag’s own system connection.
  • The verify line points to sessions, whose summary counts connections by user, database, application and client. In this capture it shows 93 idle sessions of kbdiag_ro from 127.0.0.1.

Standby not receiving WAL

This case has not been reproduced in the lab yet. The finding below is quoted from the source code, not captured. On a standby with no WAL receiver, status reports:

[WARN] inst.upstream  the standby has no WAL receiver and is not receiving WAL from the primary: if the primary fails now, no standby can take over
  verify: kbdiag slots  # run on the primary: is this standby's slot inactive?

If the receiver exists but its status is not streaming, the finding names that status instead. The exit code is 1.

Over TCP

kbdiag only reads inst.disk when it is sure it runs on the database host. That means one of:

  • the Unix socket;
  • --host set to localhost / 127.0.0.1 / ::1, with data_directory present locally. The directory check is needed because a forwarded port could lead to another machine.

Otherwise inst.disk is not_applicable. Here kbdiag connects to the primary’s own network address as kbdiag_ro:

PGPASSWORD=... ~/kbdiag status --host 192.168.105.10 -U kbdiag_ro
echo EXIT_CODE=$?
status  OK  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-09-27T13:40:08+08:00)

inst.info
  version         V008R006C009B0014
  data_directory  /home/kingbase/cluster/install/kingbase/data
  port            54321
  start_time      2026-09-20 22:19:13  (up 6d 15h)
  connections     5 / 97  (max_connections 100 - superuser_reserved 3)

inst.downstreams: 1
  name   address         state      sync
  node2  192.168.105.11  streaming  quorum

inst.upstream: not_applicable  (primary)

inst.databases: 5, total 382 MB
  test      325 MB
  esrep      15 MB
  mydb       14 MB
  kingbase   14 MB
  security   14 MB

inst.disk: not_applicable  (remote connection)
EXIT_CODE=0

not_applicable does not affect the verdict.

Without privileges

kbdiag_ro has no monitoring role. On KingbaseES V8R6 it still sees sys_stat_replication, sys_stat_wal_receiver and data_directory in full, so status gives it the same result as system. Only database sizes can be hidden. Without CONNECT on a database, that database’s size is empty and recorded in redacted. Sizes are not judged, so the verdict stays OK rather than UNKNOWN.

JSON

--json keeps raw values: sizes in bytes, times in seconds, and the version as the short number. inst.info also carries usable_connections. inst.disk carries total_bytes, used_bytes and avail_bytes. A probe that does not apply has "status": "not_applicable" and a reason, for example "primary" or "remote connection".

Exit codes

CodeMeaning
0OK
1WARN: a standby is not receiving WAL
2FAIL: all connections ordinary users may open are taken
3UNKNOWN: data not collected
64Usage error
69Cannot connect

Back to the manual

5.7 - slots: replication slots

List replication slots: who consumes them, how much WAL they keep, and whether they hold back vacuum.

Captured on 2026-09-27 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 93bf65d (static linux/amd64 binary). This is lab evidence, not production validation. The WARN example was created by a fault-injection script. It pauses the standby’s WAL receiver (SIGSTOP), so after wal_sender_timeout (30 seconds here) the primary’s slot turns inactive, as it does when a standby dies. Values belong to this capture only.

Usage

kbdiag slots [--json]

No options of its own. Connection options are the same as for sessions.

Healthy

~/kbdiag slots
echo EXIT_CODE=$?
slots  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:34:45+08:00)

slots: 1
  name           type      active            retained  xmin  xmin age  restart_lsn
  repmgr_slot_2  physical  yes (pid 903372)  0 bytes   6342  0         0/A42EE580
EXIT_CODE=0
  • active says whether something consumes the slot, and which process (here the walsender to the standby).
  • retained is the WAL this slot makes the instance keep, in 1024-based units as pg_size_pretty uses. It is measured from the current WAL position on a primary and from the replay position on a standby.
  • xmin is the oldest transaction id the slot asks the instance to keep. For this physical slot it comes from the standby’s hot_standby_feedback. xmin age is how far it lags behind the current transaction id.
  • A logical slot can also carry a catalog_xmin, which holds back vacuum of the system catalogs. That column appears only when some slot has one. (The lab runs wal_level=replica, so it has no logical slots.)

On a standby with no slots of its own:

~/kbdiag slots
echo EXIT_CODE=$?
slots  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:37:21+08:00)

slots: 0
EXIT_CODE=0

An inactive slot

~/kbdiag slots
echo EXIT_CODE=$?
slots  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:37:55+08:00)

[WARN] slot.inactive  replication slot repmgr_slot_2 is inactive, retaining 216 bytes WAL, xmin 6354 holding back the vacuum horizon
  verify: kbdiag status  # run on this slot's downstream node (usually a standby): if it cannot connect, the node is down; inst.upstream with no receiver or not streaming means it is not receiving WAL; if it shows streaming, run it again after 10-20s: a last_msg that keeps growing means the receiver is stuck

slots: 1
  name           type      active  retained   xmin  xmin age  restart_lsn
  repmgr_slot_2  physical  no      216 bytes  6354  0         0/A42FF338
EXIT_CODE=1
  • Nothing consumes an inactive slot, yet it keeps WAL, and one with an xmin stops VACUUM from removing old row versions. Being inactive is the line itself, so there is no time threshold and no option.
  • It is a WARN, not a FAIL: the application keeps working. The harm (WAL filling the disk, table bloat, no standby keeping up) comes later.
  • Right after the injection almost no WAL is retained. In a real failure it keeps growing.
  • A standby restarted by repmgr also makes its slot inactive for a few seconds, and that is reported too.
  • Drop the slot only when its downstream is really gone. kbdiag never drops it.

Following the verify line

The verify line says to run kbdiag status on the slot’s downstream node. That is usually a standby, though a standby can have downstreams of its own. On the paused standby:

~/kbdiag status
echo EXIT_CODE=$?
status  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:37:55+08:00)

inst.info
  version         V008R006C009B0014
  data_directory  /home/kingbase/cluster/install/kingbase/data
  port            54321
  start_time      2026-09-23 15:44:58  (up 3d 21h)
  connections     3 / 97  (max_connections 100 - superuser_reserved 3)

inst.upstream
  status    streaming
  upstream  192.168.105.10:54321
  slot      repmgr_slot_2
  last_msg  44s ago

inst.downstreams: 0

inst.databases: 5, total 382 MB
  test      325 MB
  esrep      15 MB
  kingbase   14 MB
  mydb       14 MB
  security   14 MB

inst.disk  (filesystem of data_directory)
  used   12 GB / 199 GB  (6%)
  free  187 GB
EXIT_CODE=0

The WAL receiver still shows streaming, because a paused process does not change its status. Run it again after 10–20 seconds, as the note says:

~/kbdiag status
echo EXIT_CODE=$?
status  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-09-27T13:38:11+08:00)

inst.info
  version         V008R006C009B0014
  data_directory  /home/kingbase/cluster/install/kingbase/data
  port            54321
  start_time      2026-09-23 15:44:58  (up 3d 21h)
  connections     3 / 97  (max_connections 100 - superuser_reserved 3)

inst.upstream
  status    streaming
  upstream  192.168.105.10:54321
  slot      repmgr_slot_2
  last_msg  1m 0s ago

inst.downstreams: 0

inst.databases: 5, total 382 MB
  test      325 MB
  esrep      15 MB
  kingbase   14 MB
  mydb       14 MB
  security   14 MB

inst.disk  (filesystem of data_directory)
  used   12 GB / 199 GB  (6%)
  free  187 GB
EXIT_CODE=0

last_msg grew from 44 seconds to 1 minute: the receiver is stuck. status does not judge last_msg, because a quiet primary only sends a message every wal_receiver_status_interval (10 seconds by default). If the node cannot be reached at all, it is down. If inst.upstream has no receiver or is not streaming, status reports that as a WARN.

Exit codes

CodeMeaning
0OK
1WARN: an inactive slot
3UNKNOWN: data not collected
64Usage error
69Cannot connect

Back to the manual

5.8 - space: disk, WAL, databases

Where the space goes: filesystems, WAL size against its settings, database and tablespace sizes.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Everything here comes from the healthy lab and from two accounts that cannot see everything: kbdiag_ro (no monitoring role) over 127.0.0.1, and kbdiag_ro over the node’s network address. No fault was injected for this command. The one FAIL it can report was not produced in the lab (see the last section). Values belong to this capture only.

Usage

kbdiag space [--json]

No options of its own. Connection options are the same as for sessions.

Healthy primary

~/kbdiag space
echo EXIT_CODE=$?
space  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:53+08:00)

disk: 1 filesystem
  holds                used   size    free    use
  data_directory, wal  15 GB  199 GB  184 GB  7%

wal: 214 files, 3248 MB
  max_wal_size       1024 MB
  wal_keep_segments  8192 MB  (512 x 16 MB)

databases: 5, total 439 MB
  test      381 MB
  esrep      15 MB
  mydb       14 MB
  kingbase   14 MB
  security   14 MB

tablespaces: 3
  name         location             size
  sys_default  (in data_directory)  467 MB
  sys_global   (in data_directory)  735 kB
  sysaudit     (in data_directory)  24 kB
EXIT_CODE=0
  • disk lists the filesystems that hold the data directory, the WAL directory and the tablespaces, with directories on the same filesystem merged into one row (by device number, so a sys_wal that is a symlink to another disk shows up as its own row). free is what a non-root user such as kingbase can use. It reads the disk with statfs, so it works only when kbdiag runs on the database host (see “Remote connection” below).
  • wal is the size of sys_wal, set beside max_wal_size and wal_keep_segments (shown as the size it keeps: 512 x 16 MB). kbdiag does not judge it: max_wal_size is a soft limit, and PG12 normally keeps about the sum of both plus the WAL written since the last checkpoint, so exceeding only one of them is normal. When sys_wal is above that sum, the text points you to kbdiag slots and kbdiag archive. Here 3248 MB is below 1024 + 8192 MB.
  • databases reuses the same probe as status, so the numbers match status.
  • tablespaces lists each one with its location (in data_directory for the default ones).

Standby

~/kbdiag space
echo EXIT_CODE=$?
space  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:00+08:00)

disk: 1 filesystem
  holds                used   size    free    use
  data_directory, wal  13 GB  199 GB  186 GB  6%

wal: 198 files, 3136 MB
  max_wal_size       1024 MB
  wal_keep_segments  8192 MB  (512 x 16 MB)

databases: 5, total 438 MB
  test      381 MB
  esrep      15 MB
  mydb       14 MB
  security   14 MB
  kingbase   14 MB

tablespaces: 3
  name         location             size
  sys_default  (in data_directory)  467 MB
  sys_global   (in data_directory)  735 kB
  sysaudit     (in data_directory)  24 kB
EXIT_CODE=0

A standby is judged the same way. Its WAL directory is its own, so the file count and size differ from the primary’s.

Without privileges

kbdiag_ro has no monitoring role. It connects over 127.0.0.1, which is TCP (hence kbdiag_ro@remote in the first line), but the database is on this host, so the disk can still be read:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro space
echo EXIT_CODE=$?
space  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-10-07T17:21:07+08:00)

disk: 1 filesystem
  holds                used   size    free    use
  data_directory, wal  15 GB  199 GB  184 GB  7%

wal: skipped  (insufficient_privilege 42501: permission denied for function sys_ls_waldir)

databases: 5, total 439 MB
  test      381 MB
  esrep      15 MB
  mydb       14 MB
  kingbase   14 MB
  security   14 MB

tablespaces: 3
  name         location             size
  sys_default  (in data_directory)  467 MB
  sys_global   (in data_directory)  ?
  sysaudit     (in data_directory)  ?
redacted: 2 rows of space.tablespaces hide size_bytes (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • wal: skipped: sys_ls_waldir is not allowed for this account, so the WAL size is not collected. space is a display command, so any probe that is not collected makes the verdict UNKNOWN instead of OK: OK would only mean “everything was collected”, and here it was not.
  • ? in the tablespace table means this account cannot see that size (pg_tablespace_size(sys_global) is denied). kbdiag wraps the call in a CASE, so only those cells are NULL and the rest of the statement still runs; the cells are listed in redacted. Granting sys_monitor lifts both.

Remote connection

Over the node’s network address the data directory may be on another machine than the one you are looking at, so kbdiag does not read a disk:

PGPASSWORD=... ~/kbdiag --host 192.168.105.10 -U kbdiag_ro space
echo EXIT_CODE=$?
space  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-10-07T17:21:10+08:00)

disk: not_applicable  (remote connection)

wal: skipped  (insufficient_privilege 42501: permission denied for function sys_ls_waldir)

databases: 5, total 439 MB
  test      381 MB
  esrep      15 MB
  mydb       14 MB
  kingbase   14 MB
  security   14 MB

tablespaces: 3
  name         location             size
  sys_default  (in data_directory)  467 MB
  sys_global   (in data_directory)  ?
  sysaudit     (in data_directory)  ?
redacted: 2 rows of space.tablespaces hide size_bytes (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • disk: not_applicable (remote connection). kbdiag reads the disk only when it is certain to run on the database host: a Unix socket, or a host of localhost, 127.0.0.1 or ::1 with the data_directory present locally. A forwarded port could lead to another machine, so the host name alone is not enough.
  • not_applicable is not a failure, but with the privilege gaps above the verdict is UNKNOWN here too.

The FAIL that was not produced

Not produced in the lab, taken from the source: space.disk_full (FAIL). It reports a filesystem holding the data directory or the WAL directory whose free space is less than one WAL segment (16 MB here). Making it appear needs the data disk to be really filled, which the lab does not do.

  • On the WAL disk no new segment can be created, so the server stops once no old segment is left to reuse. On the data directory’s disk, tables, transaction status files and temp files are about to fail to grow (these are ERRORs; the instance does not stop). The finding says which applies.
  • Strictly it is “about to be affected”, and kbdiag reports it as FAIL because there is one segment of room left and no margin to keep watching.
  • Free space on other disks (a tablespace) or “low but more than a segment” depends on the database, so it is only shown.
  • One finding per filesystem. The segment size comes from the wal probe, so when it is not collected (as for kbdiag_ro) this rule does not judge.

The status command’s inst.disk is a shorter, display-only view of the data directory’s disk.

Exit codes

CodeMeaning
0OK
2FAIL: a filesystem has less free space than one WAL segment (not produced in the lab)
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.9 - freeze: wraparound distance

How far each database is from transaction ID wraparound, and the oldest tables of this one.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Both nodes were healthy and nothing was injected, so every example is OK. The WARN and FAIL cases were not produced in the lab (see the last section). Values belong to this capture only.

Usage

kbdiag freeze [--limit N] [--json]
OptionEffect
--limit NShow at most N tables; default 20, 0 for all
--jsonPrint JSON

Connection options are the same as for sessions. --limit only trims the table list; the findings always cover every database and every table.

Healthy primary

~/kbdiag freeze
echo EXIT_CODE=$?
freeze  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:54+08:00)

limits
  autovacuum_freeze_max_age            200000000
  autovacuum_multixact_freeze_max_age  400000000
  xid stop limit                       2146483647  (new transaction IDs are refused)

databases: 7
  name       xid age  of freeze max  mxid age  xids left
  esrep      5672     0%             0         2146477975
  kingbase   5672     0%             0         2146477975
  mydb       5672     0%             0         2146477975
  security   5672     0%             0         2146477975
  template0  5672     0%             0         2146477975
  template1  5672     0%             0         2146477975
  test       5672     0%             0         2146477975

tables in test: 288, oldest first
  relation                                    kind   xid age  mxid age  heap (est.)
  information_schema.sql_features             table  5672     0         56 kB
  information_schema.sql_implementation_info  table  5672     0         8192 bytes
  information_schema.sql_languages            table  5672     0         8192 bytes
  information_schema.sql_packages             table  5672     0         8192 bytes
  information_schema.sql_parts                table  5672     0         8192 bytes
  information_schema.sql_sizing               table  5672     0         8192 bytes
  information_schema.sql_sizing_profiles      table  5672     0         0 bytes
  pg_catalog._agg                             table  5672     0         24 kB
  pg_catalog._am                              table  5672     0         8192 bytes
  pg_catalog._amop                            table  5672     0         80 kB
  pg_catalog._amproc                          table  5672     0         40 kB
  pg_catalog._anonpolicy                      table  5672     0         0 bytes
  pg_catalog._att                             table  5672     0         2024 kB
  pg_catalog._attdef                          table  5672     0         24 kB
  pg_catalog._audit_blocklog                  table  5672     0         0 bytes
  pg_catalog._audit_userlog                   table  5672     0         0 bytes
  pg_catalog._authid                          table  5672     0         8192 bytes
  pg_catalog._authmem                         table  5672     0         8192 bytes
  pg_catalog._cast                            table  5672     0         24 kB
  pg_catalog._ce_col                          table  5672     0         0 bytes
  ... 268 more not shown (--limit 0 shows all)
EXIT_CODE=0
  • limits shows the two lines kbdiag compares against, both taken from the server: autovacuum_freeze_max_age (WARN line: autovacuum must start freezing by force here) and the stop limit (FAIL line: the server refuses to hand out new transaction IDs, so write transactions fail). The stop limit is a constant of the PG12 kernel, 1 million xids before the wraparound point (2^31 - 1); for multixacts it is 100. kbdiag does not invent a threshold of its own.
  • databases is one row per database: xid age and mxid age are the age of its oldest unfrozen xid and multixact, of freeze max is the xid age as a percentage of autovacuum_freeze_max_age, and xids left is how many more transaction IDs can be handed out before the stop limit.
  • The verdict is judged per database. A database is as old as its oldest table, so reporting every table would repeat one problem dozens of times. tables is shown only for the database you are connected to, oldest first; use kbdiag -d <database> freeze for another one.
  • heap (est.) is relpages x block_size, an estimate. The exact size functions take a lock on every table, and during a rescue (VACUUM FULL, TRUNCATE are common then) they would make the whole probe wait until lock_timeout and fail.
  • Tables whose relfrozenxid is 0 (such as _kingbase_loginfo) are left out: age(0) reads as 2147483647 and would raise a false FAIL.
  • On the standby the ages are replicated and equal the primary’s (the captured output on kes-node2 shows the same 5672 for every database). A VACUUM to fix a finding must still be run on the primary.

Options as the binary prints them:

~/kbdiag freeze --help
echo EXIT_CODE=$?
How far each database is from transaction ID wraparound; the oldest tables of this one

Usage:
  kbdiag freeze [flags]

Flags:
  -h, --help        help for freeze
      --limit int   max rows to show, 0 for all (findings still cover every row) (default 20)

Global Flags:
  -d, --dbname string      database to connect to (default "test")
      --host string        server host, or socket directory (default /tmp)
      --json               print the report as JSON
  -p, --port int           server port (default 54321)
      --timeout duration   statement timeout for each query (default 10s)
  -U, --user string        database user (password from PGPASSWORD or ~/.pgpass) (default "system")
EXIT_CODE=0

WARN and FAIL: not produced in the lab

Neither finding was produced, because it would take pushing the transaction counter to hundreds of millions of xids. Taken from the source, not captured, both with the id freeze.database_age (and freeze.table_age on kbdiag table):

  • WARN: a database’s xid age is at or above autovacuum_freeze_max_age, or its multixact age is at or above autovacuum_multixact_freeze_max_age. The anti-wraparound autovacuum is due or cannot finish.
  • FAIL: the xid age is within 1 million of wraparound (or the multixact age within 100). The server refuses new transaction IDs, so writes fail.
  • Next steps point to kbdiag txn and kbdiag slots (what holds the horizon back), to kbdiag -d <database> freeze for the other databases, and to VACUUM (FREEZE) run on the primary.
  • If the limits could not be read, a FAIL can still be judged (the stop limit is a constant); below it the verdict is UNKNOWN.

Exit codes

CodeMeaning
0OK
1WARN: past autovacuum_freeze_max_age (not produced in the lab)
2FAIL: at the stop limit (not produced in the lab)
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.10 - vacuum: dead tuples and autovacuum

Which tables have the most dead tuples, whether autovacuum will clean them, and what is vacuuming now.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. The WARN example was created by an injection script: it made table public.kbdiag_inj_dead with autovacuum_enabled=off, inserted 10000 rows and deleted 5000, so the table holds 5000 dead tuples that nothing will clean. Values belong to this capture only.

Usage

kbdiag vacuum [--limit N] [--json]
OptionEffect
--limit NShow at most N tables; default 20, 0 for all
--jsonPrint JSON

Connection options are the same as for sessions. --limit only trims the table list; the findings cover every table. vacuum looks at the database you are connected to (default test).

Healthy primary

~/kbdiag vacuum
echo EXIT_CODE=$?
vacuum  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:54+08:00)

settings
  autovacuum    on  (3 workers, naptime 1m 0s)
  track_counts  on
  threshold     50 + 0.2 x reltuples

running: 0

tables in test: 98, most dead tuples first
  table                             dead  live  threshold  due  autovacuum  last autovacuum  last vacuum
  sysmac.sysmac_policy              0     0     50.2       -    on          never            never
  sysmac.sysmac_level               0     0     50.8       -    on          never            never
  sysmac.sysmac_compartment         0     0     50         -    on          never            never
  sysmac.sysmac_label               0     0     50.8       -    on          never            never
  sysmac.sysmac_policy_enforcement  0     0     50         -    on          never            never
  sysmac.sysmac_user                0     0     50         -    on          never            never
  sysmac.sysmac_obj                 0     0     50         -    on          never            never
  sysmac.sysmac_column_label        0     0     50         -    on          never            never
  sys_hm.check_type                 0     0     50.4       -    on          never            never
  sys_hm.hm_run_t                   0     0     50         -    on          never            never
  sys_hm.check_param                0     0     50.2       -    on          never            never
  sys.dual                          0     0     50.2       -    on          never            never
  sys_catalog._kingbase_loginfo     0     0     50         -    on          never            never
  public.t1                         0     0     50         -    on          never            never
  public.t_perf_test                0     0     20050      -    on          never            never
  kdb_schedule.kdb_jobagent         0     0     50         -    on          never            never
  kdb_schedule.kdb_jobclass         0     0     50         -    on          never            never
  kdb_schedule.kdb_action           0     0     50         -    on          never            never
  kdb_schedule.kdb_schedule         0     0     50         -    on          never            never
  kdb_schedule.kdb_schedule_job     0     0     50         -    on          never            never
  ... 78 more not shown (--limit 0 shows all)
EXIT_CODE=0
  • settings shows whether autovacuum and track_counts are on, the workers and naptime, and the trigger formula (threshold + scale factor x reltuples).
  • running lists VACUUMs in progress, with how far each has got (see progress). None here.
  • tables is ordered by dead tuples. threshold is the autovacuum trigger line for that table, computed the way the server does it (float4, and per-table reloptions override the global values). due says whether the dead tuples are past that line. autovacuum is the table’s own switch.
  • The list is sorted by dead tuples, and the top rows have 0, so no table is due. last autovacuum never on every table only says autovacuum never had to run on these tables since the statistics reset.

Standby

~/kbdiag vacuum
echo EXIT_CODE=$?
vacuum  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:01+08:00)

settings
  autovacuum    on  (3 workers, naptime 1m 0s)
  track_counts  on
  threshold     50 + 0.2 x reltuples

running: not_applicable  (standby: autovacuum does not run here; run on the primary)

tables in test: not_applicable  (standby: table statistics are local to each node and stay 0 here; run on the primary)
EXIT_CODE=0

Table statistics are local to each node and stay 0 on a standby, and autovacuum does not run there, so running and tables are not_applicable. The settings are still shown. Run vacuum on the primary.

A table that nobody will clean

~/kbdiag vacuum
echo EXIT_CODE=$?
vacuum  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:12+08:00)

[WARN] vacuum.table_disabled  table public.kbdiag_inj_dead has 5000 dead tuples, past its autovacuum threshold 2050, but autovacuum is off for it (autovacuum_enabled=off): nothing will clean it
  fix: VACUUM public.kbdiag_inj_dead  # connected to database test; turn autovacuum back on with ALTER TABLE ... RESET (autovacuum_enabled) unless it was turned off on purpose
  verify: kbdiag txn  # if dead tuples remain after VACUUM: the oldest transaction holding back the horizon
  verify: kbdiag slots  # or a replication slot's xmin

settings
  autovacuum    on  (3 workers, naptime 1m 0s)
  track_counts  on
  threshold     50 + 0.2 x reltuples

running: 0

tables in test: 99, most dead tuples first
  table                             dead  live  threshold  due  autovacuum  last autovacuum  last vacuum
  public.kbdiag_inj_dead            5000  5000  2050       yes  off         never            never
  sysmac.sysmac_policy              0     0     50.2       -    on          never            never
  sysmac.sysmac_level               0     0     50.8       -    on          never            never
  sysmac.sysmac_compartment         0     0     50         -    on          never            never
  sysmac.sysmac_label               0     0     50.8       -    on          never            never
  sysmac.sysmac_policy_enforcement  0     0     50         -    on          never            never
  sysmac.sysmac_user                0     0     50         -    on          never            never
  sysmac.sysmac_obj                 0     0     50         -    on          never            never
  sysmac.sysmac_column_label        0     0     50         -    on          never            never
  sys_hm.check_type                 0     0     50.4       -    on          never            never
  sys_hm.hm_run_t                   0     0     50         -    on          never            never
  sys_hm.check_param                0     0     50.2       -    on          never            never
  sys.dual                          0     0     50.2       -    on          never            never
  sys_catalog._kingbase_loginfo     0     0     50         -    on          never            never
  public.t1                         0     0     50         -    on          never            never
  public.t_perf_test                0     0     20050      -    on          never            never
  kdb_schedule.kdb_jobagent         0     0     50         -    on          never            never
  kdb_schedule.kdb_jobclass         0     0     50         -    on          never            never
  kdb_schedule.kdb_action           0     0     50         -    on          never            never
  kdb_schedule.kdb_schedule         0     0     50         -    on          never            never
  ... 79 more not shown (--limit 0 shows all)
EXIT_CODE=1
  • vacuum.table_disabled is the finding: the table has 5000 dead tuples, past its trigger line 2050, but its own autovacuum_enabled=off, so autovacuum will never clean it. The due column says yes and the autovacuum column says off.
  • It is a WARN: the dead tuples cause bloat later but nothing is broken now. The fix line is VACUUM on that table (names are quoted like quote_ident where needed); if the dead tuples are still there afterwards, something holds the horizon back, which is what the two verify lines (kbdiag txn, kbdiag slots) are for.
  • A table that is past its line while autovacuum is on is not reported. That is the normal autovacuum queue, handled once every naptime, and “waiting too long” would need a time threshold that has no objective value. It shows as due in the table only.
  • The other finding of this command, vacuum.disabled (WARN), was not produced in the lab: it means autovacuum or track_counts is off (taken from the source), so no table is vacuumed automatically any more except for the anti-wraparound vacuum. The fix is ALTER SYSTEM SET <the switch> = on followed by a reload.
  • When track_counts is off the table probe is skipped: the counters are frozen, so old values are not shown as current.

For the same table seen from the table command, see its page.

Exit codes

CodeMeaning
0OK
1WARN
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.11 - archive: WAL archiving

Whether WAL archiving works: settings, last success and failure, WAL waiting to be archived.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. No fault was injected. The primary’s WAL archiving was already failing in the lab (its archive_command runs sys_rman archive-push, and the last success was 21 days earlier), so the WARN below is what the lab really looks like; why it fails was not investigated for this page, because kbdiag does not read the server log. Values belong to this capture only.

Usage

kbdiag archive [--json]

No options of its own. Connection options are the same as for sessions.

Primary: archiving is failing

~/kbdiag archive
echo EXIT_CODE=$?
archive  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:55+08:00)

[WARN] archive.failing  archiving is failing: the last attempt failed (0000000300000000000000A3, 6s ago) and the last success was 21d 3h ago (0000000300000000000000A2); 22590 failures since the statistics reset. WAL that is not archived stays in sys_wal and is missing from the backups
  verify: kbdiag space  # how big sys_wal has grown; why archive_command fails is in the server log (log_directory)

settings
  archive_mode     always
  archive_command  export TZ=Asia/Shanghai;/home/kingbase/cluster/install/kingbase/bin/sys_rman --config /rman/kbbr_repo/sys_rman.conf --stanza=kingbase archive-push %p
  archive_timeout  0 (off)

archiver  (counting since 2026-09-15 23:12:34)
  archived  35     last 0000000300000000000000A2  21d 3h ago
  failed    22590  last 0000000300000000000000A3  6s ago

waiting: 38 .ready, 174 .done  (oldest .ready 21d 3h)
EXIT_CODE=1
  • archive.failing (WARN) fires when the last attempt failed: the last failure is later than the last success, or there has never been a success. WAL that is not archived stays in sys_wal and is missing from the backups, but the business keeps running, so it is a WARN.
  • settings shows archive_mode, archive_command and archive_timeout. kbdiag first excludes what is switched off on purpose: archive_mode=off is never judged, and archive_mode=on on a standby is not judged either, because a standby does not archive unless the mode is always.
  • archiver is the server’s archiver statistics, counted since the statistics reset time: how many succeeded and failed, and the last WAL file and how long ago for each.
  • waiting counts .ready files (WAL waiting to be archived) and .done files, and how long the oldest .ready has waited. It is display only: it must not change the verdict.
  • The verify line points to kbdiag space (how big sys_wal has grown). The reason the command fails is only in the server log (log_directory).
  • An empty archive_command is not judged: the PostgreSQL documentation says WAL then stays until a command is set, but this was not checked on KingbaseES, so the text only writes (empty).

Standby

~/kbdiag archive
echo EXIT_CODE=$?
archive  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:02+08:00)

settings
  archive_mode     always
  archive_command  export TZ=Asia/Shanghai;/home/kingbase/cluster/install/kingbase/bin/sys_rman --config /rman/kbbr_repo/sys_rman.conf --stanza=kingbase archive-push %p
  archive_timeout  0 (off)

archiver  (counting since 2026-10-07 16:49:26)
  archived  38  last 0000000300000000000000C8  2m 17s ago
  failed    0

waiting: 0 .ready, 212 .done
EXIT_CODE=0

The standby runs with archive_mode=always, so it archives too. It counts since its own start, and here it succeeds and has nothing waiting, so it is OK.

Without privileges

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro archive
echo EXIT_CODE=$?
archive  WARN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-10-07T17:21:09+08:00)

[WARN] archive.failing  archiving is failing: the last attempt failed (0000000300000000000000A3, 20s ago) and the last success was 21d 3h ago (0000000300000000000000A2); 22590 failures since the statistics reset. WAL that is not archived stays in sys_wal and is missing from the backups
  verify: kbdiag space  # how big sys_wal has grown; why archive_command fails is in the server log (log_directory)

settings
  archive_mode     always
  archive_command  export TZ=Asia/Shanghai;/home/kingbase/cluster/install/kingbase/bin/sys_rman --config /rman/kbbr_repo/sys_rman.conf --stanza=kingbase archive-push %p
  archive_timeout  0 (off)

archiver  (counting since 2026-09-15 23:12:34)
  archived  35     last 0000000300000000000000A2  21d 3h ago
  failed    22590  last 0000000300000000000000A3  20s ago

waiting: skipped  (insufficient_privilege 42501: permission denied for function sys_ls_archive_statusdir)
EXIT_CODE=1

kbdiag_ro cannot call sys_ls_archive_statusdir, so waiting is skipped. That probe is display only and is not allowed to change the verdict. The finding itself comes from the statistics view, which this account can read.

Exit codes

CodeMeaning
0OK
1WARN: the last archive attempt failed
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.12 - params: changed parameters

Which parameters are not at their default and where they are set; flags changes waiting for a restart.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. The WARN example was created by an injection script: it changed max_files_per_process (a parameter that needs a restart) with ALTER SYSTEM, reloaded the configuration, and did not restart, so the running value differs from the file. Values belong to this capture only.

Usage

kbdiag params [--json]

No options of its own, and no pattern argument: to see one parameter use ksql -c 'show x', or --json with jq. Connection options are the same as for sessions.

Healthy primary

~/kbdiag params
echo EXIT_CODE=$?
params  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:55+08:00)

pending restart: 0

changed: 63 parameters not at their default (sources other than default, override and this connection)
  this connection sets application_name, default_transaction_read_only, lock_timeout and statement_timeout itself, so their configured values are not shown; per-role and per-database settings show only for this role and database
  name                          setting                                                       unit  source              file
  archive_command               export TZ=Asia/Shanghai;/home/kingbase/cluster/install/ki...  -     configuration file  es_rep.conf:10
  archive_mode                  always                                                        -     configuration file  es_rep.conf:9
  control_file_copy             /home/kingbase/cluster/install/kingbase/copy_file             -     configuration file  es_rep.conf:11
  DateStyle                     ISO, MDY                                                      -     configuration file  kingbase.conf:654
  default_text_search_config    pg_catalog.english                                            -     configuration file  kingbase.conf:676
  dynamic_shared_memory_type    posix                                                         -     configuration file  kingbase.conf:140
  fsync                         on                                                            -     configuration file  es_rep.conf:23
  full_page_writes              on                                                            -     configuration file  es_rep.conf:3
  hot_standby                   on                                                            -     configuration file  es_rep.conf:13
  hot_standby_feedback          on                                                            -     configuration file  es_rep.conf:14
  lc_messages                   C                                                             -     configuration file  kingbase.conf:669
  lc_monetary                   en_US.UTF-8                                                   -     configuration file  kingbase.conf:671
  lc_numeric                    en_US.UTF-8                                                   -     configuration file  kingbase.conf:672
  lc_time                       en_US.UTF-8                                                   -     configuration file  kingbase.conf:673
  listen_addresses              *                                                             -     configuration file  es_rep.conf:1
  log_autovacuum_min_duration   0                                                             ms    configuration file  es_rep.conf:40
  log_checkpoints               on                                                            -     configuration file  es_rep.conf:38
  log_connections               on                                                            -     configuration file  es_rep.conf:32
  log_destination               stderr                                                        -     configuration file  es_rep.conf:44
  log_directory                 sys_log                                                       -     configuration file  kingbase.conf:432
  log_disconnections            on                                                            -     configuration file  es_rep.conf:33
  log_filename                  kingbase-%d.log                                               -     configuration file  es_rep.conf:43
  logging_collector             on                                                            -     configuration file  es_rep.conf:15
  log_line_prefix               %t [%p]: [%l-1] [%x] user=%u,db=%d,app=%a,client=%h           -     configuration file  es_rep.conf:42
  log_lock_waits                on                                                            -     configuration file  es_rep.conf:39
  log_min_duration_statement    1000                                                          ms    configuration file  es_rep.conf:47
  log_replication_commands      on                                                            -     configuration file  es_rep.conf:18
  log_rotation_age              1440                                                          min   configuration file  es_rep.conf:46
  log_statement                 ddl                                                           -     configuration file  es_rep.conf:36
  log_temp_files                0                                                             kB    configuration file  es_rep.conf:41
  log_timezone                  Asia/Shanghai                                                 -     configuration file  kingbase.conf:540
  log_truncate_on_rotation      on                                                            -     configuration file  es_rep.conf:45
  max_connections               100                                                           -     configuration file  es_rep.conf:7
  max_prepared_transactions     100                                                           -     configuration file  es_rep.conf:21
  max_replication_slots         32                                                            -     configuration file  es_rep.conf:12
  max_stack_depth               3072                                                          kB    configuration file  kingbase.conf:133
  max_wal_senders               32                                                            -     configuration file  es_rep.conf:5
  max_wal_size                  1024                                                          MB    configuration file  kingbase.conf:224
  min_wal_size                  80                                                            MB    configuration file  kingbase.conf:225
  ora_input_emptystr_isnull     on                                                            -     configuration file  kingbase.conf:767
  ora_integer_div_returnfloat   on                                                            -     configuration file  kingbase.conf:768
  password_encryption           scram-sha-256                                                 -     configuration file  kingbase.conf:91
  port                          54321                                                         -     configuration file  es_rep.conf:2
  primary_conninfo              user=esrep connect_timeout=10 host=192.168.105.11 port=54...  -     configuration file  kingbase.auto.conf:3
  primary_slot_name             repmgr_slot_1                                                 -     configuration file  kingbase.auto.conf:4
  shared_buffers                65536                                                         8kB   configuration file  es_rep.conf:22
  shared_preload_libraries      repmgr, synonym, plsql, force_view, kdb_flashback,plugin_...  -     configuration file  kingbase.conf:766
  synchronous_commit            remote_apply                                                  -     configuration file  es_rep.conf:20
  synchronous_standby_names     ANY 1( node2)                                                 -     configuration file  kingbase.auto.conf:7
  sys_stat_statements.track     none                                                          -     configuration file  kingbase.auto.conf:5
  tcp_keepalives_count          0                                                             -     configuration file  es_rep.conf:27
  tcp_keepalives_idle           0                                                             s     configuration file  es_rep.conf:25
  tcp_keepalives_interval       0                                                             s     configuration file  es_rep.conf:26
  tcp_user_timeout              0                                                             ms    configuration file  es_rep.conf:28
  TimeZone                      PRC                                                           -     configuration file  es_rep.conf:24
  track_real_stats              on                                                            -     configuration file  kingbase.auto.conf:6
  wal_compression               on                                                            -     configuration file  es_rep.conf:19
  wal_keep_segments             512                                                           -     configuration file  es_rep.conf:6
  wal_level                     replica                                                       -     configuration file  es_rep.conf:8
  wal_log_hints                 on                                                            -     configuration file  es_rep.conf:4
  wal_receiver_status_interval  2                                                             s     configuration file  kingbase.conf:323
  wal_receiver_timeout          30000                                                         ms    configuration file  es_rep.conf:30
  wal_sender_timeout            30000                                                         ms    configuration file  es_rep.conf:29
EXIT_CODE=0
  • pending restart lists the parameters whose file value differs from what is running (the server’s own pending_restart flag). None here.
  • changed lists only what someone set: sources other than default, override (fixed at compile or initdb time) and this connection’s own client/session (those are kbdiag’s own settings and would be noise). file is the file and line that set it.
  • The line under changed names the two limits of what can be seen. kbdiag sets application_name, default_transaction_read_only, lock_timeout and statement_timeout itself on its connection, so their configured values are not shown. Per-role and per-database settings show only for this role and database.
  • Long values such as archive_command are cut with ...; --json has them in full.
  • The standby shows a similar list, with primary_conninfo, primary_slot_name and synchronous_standby_names differing (captured on kes-node2; 63 parameters changed there too).

Without privileges

kbdiag_ro (no monitoring role, over 127.0.0.1):

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro params
echo EXIT_CODE=$?
params  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-10-07T17:21:08+08:00)

pending restart: 0

changed: 59 parameters not at their default (sources other than default, override and this connection)
  this connection sets application_name, default_transaction_read_only, lock_timeout and statement_timeout itself, so their configured values are not shown; per-role and per-database settings show only for this role and database
  name                          setting                                                       unit  source              file
  archive_command               export TZ=Asia/Shanghai;/home/kingbase/cluster/install/ki...  -     configuration file  ?
  archive_mode                  always                                                        -     configuration file  ?
  control_file_copy             /home/kingbase/cluster/install/kingbase/copy_file             -     configuration file  ?
  DateStyle                     ISO, MDY                                                      -     configuration file  ?
  default_text_search_config    pg_catalog.english                                            -     configuration file  ?
  dynamic_shared_memory_type    posix                                                         -     configuration file  ?
  fsync                         on                                                            -     configuration file  ?
  full_page_writes              on                                                            -     configuration file  ?
  hot_standby                   on                                                            -     configuration file  ?
  hot_standby_feedback          on                                                            -     configuration file  ?
  lc_messages                   C                                                             -     configuration file  ?
  lc_monetary                   en_US.UTF-8                                                   -     configuration file  ?
  lc_numeric                    en_US.UTF-8                                                   -     configuration file  ?
  lc_time                       en_US.UTF-8                                                   -     configuration file  ?
  listen_addresses              *                                                             -     configuration file  ?
  log_autovacuum_min_duration   0                                                             ms    configuration file  ?
  log_checkpoints               on                                                            -     configuration file  ?
  log_connections               on                                                            -     configuration file  ?
  log_destination               stderr                                                        -     configuration file  ?
  log_disconnections            on                                                            -     configuration file  ?
  logging_collector             on                                                            -     configuration file  ?
  log_line_prefix               %t [%p]: [%l-1] [%x] user=%u,db=%d,app=%a,client=%h           -     configuration file  ?
  log_lock_waits                on                                                            -     configuration file  ?
  log_min_duration_statement    1000                                                          ms    configuration file  ?
  log_replication_commands      on                                                            -     configuration file  ?
  log_rotation_age              1440                                                          min   configuration file  ?
  log_statement                 ddl                                                           -     configuration file  ?
  log_temp_files                0                                                             kB    configuration file  ?
  log_timezone                  Asia/Shanghai                                                 -     configuration file  ?
  log_truncate_on_rotation      on                                                            -     configuration file  ?
  max_connections               100                                                           -     configuration file  ?
  max_prepared_transactions     100                                                           -     configuration file  ?
  max_replication_slots         32                                                            -     configuration file  ?
  max_stack_depth               3072                                                          kB    configuration file  ?
  max_wal_senders               32                                                            -     configuration file  ?
  max_wal_size                  1024                                                          MB    configuration file  ?
  min_wal_size                  80                                                            MB    configuration file  ?
  ora_input_emptystr_isnull     on                                                            -     configuration file  ?
  ora_integer_div_returnfloat   on                                                            -     configuration file  ?
  password_encryption           scram-sha-256                                                 -     configuration file  ?
  port                          54321                                                         -     configuration file  ?
  primary_slot_name             repmgr_slot_1                                                 -     configuration file  ?
  shared_buffers                65536                                                         8kB   configuration file  ?
  synchronous_commit            remote_apply                                                  -     configuration file  ?
  synchronous_standby_names     ANY 1( node2)                                                 -     configuration file  ?
  sys_stat_statements.track     none                                                          -     configuration file  ?
  tcp_keepalives_count          3                                                             -     configuration file  ?
  tcp_keepalives_idle           2                                                             s     configuration file  ?
  tcp_keepalives_interval       2                                                             s     configuration file  ?
  tcp_user_timeout              9000                                                          ms    configuration file  ?
  TimeZone                      PRC                                                           -     configuration file  ?
  track_real_stats              on                                                            -     configuration file  ?
  wal_compression               on                                                            -     configuration file  ?
  wal_keep_segments             512                                                           -     configuration file  ?
  wal_level                     replica                                                       -     configuration file  ?
  wal_log_hints                 on                                                            -     configuration file  ?
  wal_receiver_status_interval  2                                                             s     configuration file  ?
  wal_receiver_timeout          30000                                                         ms    configuration file  ?
  wal_sender_timeout            30000                                                         ms    configuration file  ?
  only the parameters this account may read: superuser-only ones are not listed
redacted: 59 rows of params.changed hide sourcefile, sourceline (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3
  • file is ?: this account cannot see sourcefile and sourceline. They are recorded under redacted.
  • The list is shorter (59 instead of 63) because superuser-only parameters are not visible to this account at all, and the text says so on its last line. Their pending_restart flag is invisible too, so with no finding the verdict is UNKNOWN: kbdiag will not say OK about something it cannot see.

A change waiting for a restart

~/kbdiag params
echo EXIT_CODE=$?
params  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:15+08:00)

[WARN] params.pending_restart  parameter max_files_per_process was changed but the instance still runs with 1000: the new value takes effect only after a restart, the next one included
  verify: select sourcefile, sourceline, setting, applied, error from sys_file_settings where name = 'max_files_per_process'  # the value waiting in the file (needs a superuser)
  fix: ALTER SYSTEM SET max_files_per_process = '1000'  # if the change was not meant: writes the running value back; after SELECT sys_reload_conf() the flag clears (a reload clears it only when the file's value equals the running one, so ALTER SYSTEM RESET alone leaves it until a restart). Otherwise plan the restart

pending restart: 1
  name                   running  file
  max_files_per_process  1000     -

changed: 64 parameters not at their default (sources other than default, override and this connection)
  this connection sets application_name, default_transaction_read_only, lock_timeout and statement_timeout itself, so their configured values are not shown; per-role and per-database settings show only for this role and database
  name                          setting                                                       unit  source              file
  archive_command               export TZ=Asia/Shanghai;/home/kingbase/cluster/install/ki...  -     configuration file  es_rep.conf:10
  archive_mode                  always                                                        -     configuration file  es_rep.conf:9
  control_file_copy             /home/kingbase/cluster/install/kingbase/copy_file             -     configuration file  es_rep.conf:11
  DateStyle                     ISO, MDY                                                      -     configuration file  kingbase.conf:654
  default_text_search_config    pg_catalog.english                                            -     configuration file  kingbase.conf:676
  dynamic_shared_memory_type    posix                                                         -     configuration file  kingbase.conf:140
  fsync                         on                                                            -     configuration file  es_rep.conf:23
  full_page_writes              on                                                            -     configuration file  es_rep.conf:3
  hot_standby                   on                                                            -     configuration file  es_rep.conf:13
  hot_standby_feedback          on                                                            -     configuration file  es_rep.conf:14
  lc_messages                   C                                                             -     configuration file  kingbase.conf:669
  lc_monetary                   en_US.UTF-8                                                   -     configuration file  kingbase.conf:671
  lc_numeric                    en_US.UTF-8                                                   -     configuration file  kingbase.conf:672
  lc_time                       en_US.UTF-8                                                   -     configuration file  kingbase.conf:673
  listen_addresses              *                                                             -     configuration file  es_rep.conf:1
  log_autovacuum_min_duration   0                                                             ms    configuration file  es_rep.conf:40
  log_checkpoints               on                                                            -     configuration file  es_rep.conf:38
  log_connections               on                                                            -     configuration file  es_rep.conf:32
  log_destination               stderr                                                        -     configuration file  es_rep.conf:44
  log_directory                 sys_log                                                       -     configuration file  kingbase.conf:432
  log_disconnections            on                                                            -     configuration file  es_rep.conf:33
  log_filename                  kingbase-%d.log                                               -     configuration file  es_rep.conf:43
  logging_collector             on                                                            -     configuration file  es_rep.conf:15
  log_line_prefix               %t [%p]: [%l-1] [%x] user=%u,db=%d,app=%a,client=%h           -     configuration file  es_rep.conf:42
  log_lock_waits                on                                                            -     configuration file  es_rep.conf:39
  log_min_duration_statement    1000                                                          ms    configuration file  es_rep.conf:47
  log_replication_commands      on                                                            -     configuration file  es_rep.conf:18
  log_rotation_age              1440                                                          min   configuration file  es_rep.conf:46
  log_statement                 ddl                                                           -     configuration file  es_rep.conf:36
  log_temp_files                0                                                             kB    configuration file  es_rep.conf:41
  log_timezone                  Asia/Shanghai                                                 -     configuration file  kingbase.conf:540
  log_truncate_on_rotation      on                                                            -     configuration file  es_rep.conf:45
  max_connections               100                                                           -     configuration file  es_rep.conf:7
  max_files_per_process         1000                                                          -     default             -
  max_prepared_transactions     100                                                           -     configuration file  es_rep.conf:21
  max_replication_slots         32                                                            -     configuration file  es_rep.conf:12
  max_stack_depth               3072                                                          kB    configuration file  kingbase.conf:133
  max_wal_senders               32                                                            -     configuration file  es_rep.conf:5
  max_wal_size                  1024                                                          MB    configuration file  kingbase.conf:224
  min_wal_size                  80                                                            MB    configuration file  kingbase.conf:225
  ora_input_emptystr_isnull     on                                                            -     configuration file  kingbase.conf:767
  ora_integer_div_returnfloat   on                                                            -     configuration file  kingbase.conf:768
  password_encryption           scram-sha-256                                                 -     configuration file  kingbase.conf:91
  port                          54321                                                         -     configuration file  es_rep.conf:2
  primary_conninfo              user=esrep connect_timeout=10 host=192.168.105.11 port=54...  -     configuration file  kingbase.auto.conf:3
  primary_slot_name             repmgr_slot_1                                                 -     configuration file  kingbase.auto.conf:4
  shared_buffers                65536                                                         8kB   configuration file  es_rep.conf:22
  shared_preload_libraries      repmgr, synonym, plsql, force_view, kdb_flashback,plugin_...  -     configuration file  kingbase.conf:766
  synchronous_commit            remote_apply                                                  -     configuration file  es_rep.conf:20
  synchronous_standby_names     ANY 1( node2)                                                 -     configuration file  kingbase.auto.conf:7
  sys_stat_statements.track     none                                                          -     configuration file  kingbase.auto.conf:5
  tcp_keepalives_count          0                                                             -     configuration file  es_rep.conf:27
  tcp_keepalives_idle           0                                                             s     configuration file  es_rep.conf:25
  tcp_keepalives_interval       0                                                             s     configuration file  es_rep.conf:26
  tcp_user_timeout              0                                                             ms    configuration file  es_rep.conf:28
  TimeZone                      PRC                                                           -     configuration file  es_rep.conf:24
  track_real_stats              on                                                            -     configuration file  kingbase.auto.conf:6
  wal_compression               on                                                            -     configuration file  es_rep.conf:19
  wal_keep_segments             512                                                           -     configuration file  es_rep.conf:6
  wal_level                     replica                                                       -     configuration file  es_rep.conf:8
  wal_log_hints                 on                                                            -     configuration file  es_rep.conf:4
  wal_receiver_status_interval  2                                                             s     configuration file  kingbase.conf:323
  wal_receiver_timeout          30000                                                         ms    configuration file  es_rep.conf:30
  wal_sender_timeout            30000                                                         ms    configuration file  es_rep.conf:29
EXIT_CODE=1
  • params.pending_restart is a WARN, one per parameter. The line is the server’s own pending_restart flag. The business is not affected now: the instance still runs the old value. But the next restart, including one after a failover, will suddenly switch to the new value.
  • pending restart shows the running value; the value waiting in the file is shown as - here. The verify line gives a query for it (sys_file_settings; it needs a superuser).
  • The fix line writes the running value back with ALTER SYSTEM SET x = '<running value>' and then SELECT sys_reload_conf(). In PostgreSQL 12 a reload clears the pending flag only when the file’s value equals the running value, so ALTER SYSTEM RESET alone would leave the flag until the next restart. If the change was meant, plan the restart instead.
  • max_files_per_process is listed in changed with source default: a parameter that waits for a restart is listed whatever its source, because after the change its source still reads default.
  • Config file errors (sys_file_settings.error) are not checked: kbdiag_ro cannot read that view.

Exit codes

CodeMeaning
0OK
1WARN: a parameter change waits for a restart
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.13 - repl: replication from this node

Replication from this node: each standby’s lag and the synchronous settings on a primary; receive and replay on a standby.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. The WARN example was created by a fault-injection script that pauses the standby’s WAL receiver (SIGSTOP), the same one used on the slots page. Values belong to this capture only.

Usage

kbdiag repl [--json]

No options of its own. Connection options are the same as for sessions.

Primary

~/kbdiag repl
echo EXIT_CODE=$?
repl  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:56+08:00)

sync
  synchronous_standby_names  ANY 1( node2)  (any 1 of node2 must confirm)
  synchronous_commit         remote_apply
  synchronous now            1 (node2)

downstreams: 1  (bytes behind this node's current WAL position)
  name   address         state      sync    sent     flushed  replayed  replay lag  last reply
  node2  192.168.105.11  streaming  quorum  0 bytes  0 bytes  0 bytes   0s          1s ago
EXIT_CODE=0
  • sync shows synchronous_standby_names and what it means (any 1 of node2 must confirm), synchronous_commit, and how many standbys the server currently counts as synchronous. quorum in the sync column is the server’s own sync_state; repmgr reports quorum here rather than sync or async, so kbdiag does not translate it.
  • downstreams is one row per standby: the position it has been sent, flushed and replayed, as bytes behind this node’s current WAL position, the replay lag in time (empty when the standby is caught up and idle), and how long ago it last replied.
  • Lag is shown, not judged. There is no objective line on the server for it.

Standby

~/kbdiag repl
echo EXIT_CODE=$?
repl  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:03+08:00)

upstream
  status    streaming
  upstream  192.168.105.10:54321
  slot      repmgr_slot_2
  last_msg  3s ago

replay
  received                   0/C9352A80
  replayed                   0/C9352A80  (caught up with what was received)
  last replayed transaction  1m 0s ago
  paused                     no

downstreams: 0
EXIT_CODE=0
  • upstream is the same WAL receiver view as kbdiag status (inst.upstream), with last_msg the time since the last message from the primary.
  • replay compares what was received with what was replayed. caught up with what was received means the two positions are equal. last replayed transaction 1m 0s ago is not a delay: on an idle primary it can read hours while the positions are identical, so kbdiag does not use it as a lag.
  • paused is whether replay was paused with sys_wal_replay_pause().

A stuck WAL receiver

With the standby’s receiver paused, the standby reports:

~/kbdiag repl
echo EXIT_CODE=$?
repl  WARN  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:22:58+08:00)

[WARN] inst.upstream  the standby's WAL receiver shows streaming, but nothing has come from the primary for 1m 12s, longer than wal_receiver_timeout (30s), after which a working receiver reconnects: it is stuck (stopped or blocked), so it is not receiving WAL: if the primary fails now, no standby can take over
  verify: kbdiag slots  # run on the primary: is this standby's slot inactive?

upstream
  status    streaming
  upstream  192.168.105.10:54321
  slot      repmgr_slot_2
  last_msg  1m 12s ago

replay
  received                   0/CCCC9228
  replayed                   0/CCCC9228  (caught up with what was received)
  last replayed transaction  1m 12s ago
  paused                     no

downstreams: 0
EXIT_CODE=1
  • The finding is inst.upstream, the same rule kbdiag status uses: the receiver says streaming, but last_msg is older than wal_receiver_timeout (30 s in the lab). A working receiver asks the primary for a reply at half that time and reconnects when it is full, so only a stuck one gets past it. Without a receiver, or in a state other than streaming, the same finding fires.
  • The received and replayed positions stay equal: nothing arrived, so there is nothing to replay. It is the age of the last message that shows it.
  • Known edge: the receiver sets its receive time at connection start, so a slow connection (more than half the timeout) or a timeline switch can raise this finding once for a moment. There is no margin on purpose, because no objective value for one exists.

The primary at the same moment:

~/kbdiag repl
echo EXIT_CODE=$?
repl  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:22:56+08:00)

sync
  synchronous_standby_names  (none: asynchronous only)
  synchronous_commit         remote_apply

downstreams: 0
EXIT_CODE=0
  • The standby is gone from downstreams (0), and synchronous_standby_names now reads (none: asynchronous only); it was ANY 1( node2) before the injection. So repl.sync_short did not fire. kbdiag shows what the server has; the the setting changed during the injection because repmgr changed it: with synchronous='quorum' in repmgr.conf, repmgrd clears synchronous_standby_names about 2 seconds after the standby disconnects (falling back to asynchronous commits) and restores it when the standby reconnects (seen in the lab’s hamgr.log, 2026-09-28). It is repmgr, not KingbaseES itself. So on this kind of cluster repl.sync_short shows only in that short window; the usual state after a standby is lost is “already asynchronous”, which repl shows as (none: asynchronous only).
  • Use slots on the primary to see the slot turned inactive, and cluster for repmgr’s view.

WARN findings not produced in the lab

Taken from the source, not captured:

  • repl.replay_paused (WARN): replay is paused on a standby (sys_wal_replay_pause()). Queries still run, but it falls further behind and a failover would have to replay everything received first. The fix is SELECT sys_wal_replay_resume() unless it was paused on purpose. It has no injection in the lab: pausing replay there blocks every commit on the primary (synchronous_commit is remote_apply).
  • repl.sync_short (WARN): synchronous_standby_names needs more standbys than the server counts as synchronous candidates (sync or quorum). The text says commits either wait or the server has stopped waiting, so the synchronous copy is not guaranteed. It is a WARN rather than FAIL because in the lab, commits went through after the standby disconnected (repmgr had switched to asynchronous, see above). kbdiag counts the server’s own sync_state instead of redoing the candidate rules, and it judges only when synchronous_commit makes commits wait for a standby (this connection’s value; per-role or per-database settings are not visible).

Exit codes

CodeMeaning
0OK
1WARN: no WAL being received, replay paused, or too few synchronous standbys
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.14 - cluster: repmgr's view

repmgr’s view of the cluster (nodes, roles, upstreams, latest events), checked against this node.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. The cluster is managed by repmgr, with its metadata in database esrep. The WARN example was created by the fault-injection script that pauses the standby’s WAL receiver (SIGSTOP) until the standby is no longer attached to the primary, the same one used on the slots page. Values belong to this capture only.

Usage

kbdiag cluster [--json]

No options of its own. Connection options are the same as for sessions, with one difference: without -d, cluster connects to database esrep, where repmgr keeps its metadata. kbdiag holds only one connection, so it does not open a second one for it. If there is no esrep database it falls back to the default database (not exit code 69, which only means the instance cannot be reached). It does not run the repmgr binaries, so the per-node Status column of repmgr cluster show (which connects to each node) is not available.

Primary

~/kbdiag cluster
echo EXIT_CODE=$?
cluster  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:56+08:00)

nodes: 2  (repmgr metadata in database esrep)
  id  name   type     upstream  active  priority  location  slot
  1   node1  primary  -         yes     100       default   repmgr_slot_1
  2   node2  standby  node1     yes     100       default   repmgr_slot_2
  this node is node1: repmgr says primary, the database is a primary
  attached here: node2

events: 20  (the latest, at most 20)
  time                 node   event                   ok   details
  2026-10-07 17:20:02  node2  standby_recovery        yes  reconnected to local node "node2" (ID: 2), marking active
  2026-10-07 17:20:01  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 17:20:01  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 43 seconds
  2026-10-07 17:19:18  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:12:14  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 6 seconds
  2026-10-07 17:12:08  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:01:21  node2  standby_recovery        yes  reconnected to local node "node2" (ID: 2), marking active
  2026-10-07 17:01:21  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 43 seconds
  2026-10-07 17:01:19  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 17:00:38  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 16:49:31  node1  child_node_new_connect  yes  new standby "node2" (ID: 2) has connected
  2026-10-07 16:49:28  node2  repmgrd_start           yes  monitoring connection to upstream node "node1" (ID: 1)
  2026-10-07 16:49:26  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 16:49:26  node2  node_rejoin             yes  node 2 is now attached to node 1
  2026-10-07 16:48:36  node1  repmgrd_start           yes  monitoring cluster primary "node1" (ID: 1)
  2026-09-29 20:06:21  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 8 seconds
  2026-09-29 20:06:13  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-09-29 19:22:45  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 6 seconds
  2026-09-29 19:22:38  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-09-28 15:42:40  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 106 seconds
EXIT_CODE=0
  • nodes is repmgr’s node table: type, upstream, active, priority, location and replication slot. The text marks which node this is, using repmgr’s get_local_node_id() first and the primary_slot_name (repmgr_slot_N) otherwise. If it cannot tell which node it is, it does not compare roles and the verdict is not OK.
  • The line this node is node1: repmgr says primary, the database is a primary is the comparison between repmgr’s metadata and what the database itself says. attached here: node2 is the standbys repmgr says follow this node that really have a walsender here.
  • events is the latest 20 repmgr events. The disconnect and reconnect events in the list are from earlier test runs in this lab.
  • A node that is up or not, and whether repmgrd is running, are not visible from one database; run kbdiag status on each node.
  • The conninfo is not collected: it may contain a password.

Standby

~/kbdiag cluster
echo EXIT_CODE=$?
cluster  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:03+08:00)

nodes: 2  (repmgr metadata in database esrep)
  id  name   type     upstream  active  priority  location  slot
  1   node1  primary  -         yes     100       default   repmgr_slot_1
  2   node2  standby  node1     yes     100       default   repmgr_slot_2
  this node is node2: repmgr says standby, the database is a standby

events: 20  (the latest, at most 20)
  time                 node   event                   ok   details
  2026-10-07 17:20:02  node2  standby_recovery        yes  reconnected to local node "node2" (ID: 2), marking active
  2026-10-07 17:20:01  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 17:20:01  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 43 seconds
  2026-10-07 17:19:18  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:12:14  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 6 seconds
  2026-10-07 17:12:08  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:01:21  node2  standby_recovery        yes  reconnected to local node "node2" (ID: 2), marking active
  2026-10-07 17:01:21  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 43 seconds
  2026-10-07 17:01:19  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 17:00:38  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 16:49:31  node1  child_node_new_connect  yes  new standby "node2" (ID: 2) has connected
  2026-10-07 16:49:28  node2  repmgrd_start           yes  monitoring connection to upstream node "node1" (ID: 1)
  2026-10-07 16:49:26  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 16:49:26  node2  node_rejoin             yes  node 2 is now attached to node 1
  2026-10-07 16:48:36  node1  repmgrd_start           yes  monitoring cluster primary "node1" (ID: 1)
  2026-09-29 20:06:21  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 8 seconds
  2026-09-29 20:06:13  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-09-29 19:22:45  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 6 seconds
  2026-09-29 19:22:38  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-09-28 15:42:40  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 106 seconds
EXIT_CODE=0

The standby’s repmgr metadata is replicated from the primary, so the node table and the events are the same. Only the comparison line is its own. cluster.detached is judged on the primary only.

An explicit -d

~/kbdiag -d test cluster
echo EXIT_CODE=$?
cluster  UNKNOWN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:11+08:00)

nodes: skipped  (no repmgr schema in database test named by -d; repmgr keeps it in database esrep by default)

events: skipped  (no repmgr schema in database test named by -d; repmgr keeps it in database esrep by default)
EXIT_CODE=3

When you give -d yourself, kbdiag trusts it. Database test has no repmgr schema, so both probes are skipped, which makes the verdict UNKNOWN (without -d the same absence would be not_applicable: not a repmgr cluster, or the metadata is somewhere else). The text says where repmgr keeps its data by default.

A standby that is not attached

~/kbdiag cluster
echo EXIT_CODE=$?
cluster  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:22:57+08:00)

[WARN] cluster.detached  repmgr lists node2 as an active standby of this node (node1), but no walsender here has that application_name: it is not attached (repmgr cluster show would report it so), unless its conninfo sets another application_name
  verify: kbdiag status  # run on node2: is it up, is it receiving WAL
  verify: kbdiag slots  # whether its slot here is inactive

nodes: 2  (repmgr metadata in database esrep)
  id  name   type     upstream  active  priority  location  slot
  1   node1  primary  -         yes     100       default   repmgr_slot_1
  2   node2  standby  node1     yes     100       default   repmgr_slot_2
  this node is node1: repmgr says primary, the database is a primary
  not attached here: node2

events: 20  (the latest, at most 20)
  time                 node   event                   ok   details
  2026-10-07 17:22:20  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:20:02  node2  standby_recovery        yes  reconnected to local node "node2" (ID: 2), marking active
  2026-10-07 17:20:01  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 17:20:01  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 43 seconds
  2026-10-07 17:19:18  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:12:14  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 6 seconds
  2026-10-07 17:12:08  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 17:01:21  node2  standby_recovery        yes  reconnected to local node "node2" (ID: 2), marking active
  2026-10-07 17:01:21  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 43 seconds
  2026-10-07 17:01:19  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 17:00:38  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-10-07 16:49:31  node1  child_node_new_connect  yes  new standby "node2" (ID: 2) has connected
  2026-10-07 16:49:28  node2  repmgrd_start           yes  monitoring connection to upstream node "node1" (ID: 1)
  2026-10-07 16:49:26  node1  node_recovery_success   yes  node "node2" (ID: 2) auto-recovery success
  2026-10-07 16:49:26  node2  node_rejoin             yes  node 2 is now attached to node 1
  2026-10-07 16:48:36  node1  repmgrd_start           yes  monitoring cluster primary "node1" (ID: 1)
  2026-09-29 20:06:21  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 8 seconds
  2026-09-29 20:06:13  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
  2026-09-29 19:22:45  node1  child_node_reconnect    yes  standby node "node2" (ID: 2) has reconnected after 6 seconds
  2026-09-29 19:22:38  node1  child_node_disconnect   yes  standby node "node2" (ID: 2) has disconnected
EXIT_CODE=1
  • cluster.detached (WARN): repmgr still lists node2 as an active standby of this node, but no walsender here has that application name, so it is not attached. repmgr would report it so too, unless the standby’s conninfo sets another application_name. The text line not attached here: node2 is the same fact.
  • The newest event, child_node_disconnect at 17:22:20, is repmgr’s own record of the same thing.
  • It is a WARN: the business is not hit yet. Whether it is really down or only stuck shows only on the node itself, so the verify lines say to run kbdiag status on node2 and kbdiag slots here.

WARN findings not produced in the lab

Taken from the source, not captured. All are WARN, because repmgr acts on its metadata and a mismatch is a risk, but the business is not affected yet; whether it is a real split brain shows only on each node.

  • cluster.primaries: repmgr lists more than one active primary. Its metadata says split brain; run kbdiag status on each to see which one is out of recovery.
  • cluster.inactive: repmgr marks a node inactive, counted as failed or removed, so the cluster has one node less to fail over to.
  • cluster.role_mismatch: repmgr says this node is a primary (or standby), but the database is the other.

Exit codes

CodeMeaning
0OK
1WARN
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.15 - top-objects: largest tables and indexes

The largest tables (heap, indexes, TOAST) and indexes of this database.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Nothing was injected. Values belong to this capture only.

Usage

kbdiag top-objects [--limit N] [--json]
OptionEffect
--limit NShow at most N rows per list; default 20, 0 for all
--jsonPrint JSON

Connection options are the same as for sessions and it looks at the database you are connected to. This command only shows; it has no findings.

Primary

~/kbdiag top-objects
echo EXIT_CODE=$?
top-objects  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:57+08:00)

tables in test: 207, largest first  (total = heap + indexes + TOAST)
  table                       kind   total    heap     indexes  toast       rows (est.)
  public.orders               table  170 MB   62 MB    108 MB   -           1000000
  public.flight_psg_new_info  table  107 MB   64 MB    43 MB    -           1000000
  public.kbdiag_test          table  71 MB    43 MB    28 MB    8192 bytes  645750
  public.t_perf_test          table  8968 kB  6752 kB  2216 kB  -           100000
  pg_catalog._proc            table  4624 kB  1480 kB  712 kB   2432 kB     4650
  pg_catalog._dep             table  3816 kB  1160 kB  2656 kB  -           18518
  pg_catalog._att             table  3560 kB  2056 kB  1504 kB  -           11678
  pg_catalog._rewrite         table  2320 kB  664 kB   88 kB    1568 kB     576
  pg_catalog._desc            table  1616 kB  1296 kB  312 kB   8192 bytes  4923
  pg_catalog._stat            table  728 kB   520 kB   48 kB    160 kB      633
  pg_catalog._rel             table  640 kB   352 kB   288 kB   -           1244
  pg_catalog._typ             table  464 kB   272 kB   184 kB   8192 bytes  1304
  pg_catalog._op              table  328 kB   216 kB   112 kB   -           1062
  pg_catalog._amop            table  288 kB   112 kB   176 kB   -           1266
  pg_catalog._pkg             table  248 kB   64 kB    32 kB    152 kB      6
  pg_catalog._con             table  184 kB   80 kB    96 kB    8192 bytes  136
  pg_catalog._ind             table  176 kB   112 kB   64 kB    -           353
  pg_catalog._initprivs       table  168 kB   112 kB   48 kB    8192 bytes  777
  pg_catalog._amproc          table  160 kB   72 kB    88 kB    -           641
  pg_catalog._trigger         table  144 kB   64 kB    72 kB    8192 bytes  192
  ... 187 more not shown (--limit 0 shows all)

indexes in test: 271, largest first
  index                                     table                size
  public.kbdiag_rev_idx                     orders               56 MB
  public.idx_orders_user_status             orders               30 MB
  public.kbdiag_test_pkey                   kbdiag_test          28 MB
  public.flight_psg_new_info_pkey           flight_psg_new_info  22 MB
  public.idx_homs_flight_psg_new_info_tm    flight_psg_new_info  22 MB
  public.orders_pkey                        orders               22 MB
  public.t_perf_test_pkey                   t_perf_test          2216 kB
  pg_catalog._dep_depender_index            _dep                 1384 kB
  pg_catalog._dep_reference_index           _dep                 1224 kB
  pg_catalog._att_relid_attnam_index        _att                 888 kB
  pg_catalog._proc_proname_args_nsp_index   _proc                576 kB
  pg_catalog._att_relid_attnum_index        _att                 568 kB
  pg_catalog._desc_o_c_o_index              _desc                288 kB
  pg_catalog._proc_oid_index                _proc                136 kB
  pg_catalog._rel_relname_nsp_index         _rel                 104 kB
  pg_catalog._rel_tblspc_relfilenode_index  _rel                 88 kB
  pg_catalog._typ_typname_nsp_index         _typ                 88 kB
  pg_catalog._amop_fam_strat_index          _amop                72 kB
  pg_catalog._op_oprname_l_r_n_index        _op                  72 kB
  pg_catalog._rel_oid_index                 _rel                 72 kB
  ... 251 more not shown (--limit 0 shows all)
EXIT_CODE=0
  • tables ordered by total size. total is the heap, indexes and TOAST added together: total = heap + indexes + toast. The split answers “is it big because of data, indexes or large columns”, and the remedies differ. heap is pg_table_size minus TOAST, so it includes the free space and visibility maps. A TOAST table and its index are not listed on their own; they count under the parent table.
  • Sizes are exact, not relpages estimates (the opposite of freeze): this command’s whole point is “who takes space now”, and after a bulk load without ANALYZE relpages is stale. The cost is that the size functions take an AccessShareLock, so when a table is held by something like VACUUM FULL the whole probe is skipped at lock_timeout with the reason written out, instead of showing partial results. A table dropped while the query runs reads NULL and is filtered out, so an ETL that creates and drops temporary tables does not fail the probe.
  • rows (est.) is reltuples.
  • indexes lists the largest indexes with the table they belong to. Size is the whole point, so the usage count is on kbdiag table <name>.
  • Partitions are not summed up to their parent.
  • No judgment: how big is too big has no objective line. So the verdict is OK only when everything was collected; an uncollected probe makes it UNKNOWN.
  • The lab shows the bulk of the space in tables created for tests (orders, flight_psg_new_info, kbdiag_test).

Standby and without privileges

The standby and a kbdiag_ro account (no monitoring role, over 127.0.0.1) return the same rows as the primary in the lab; only the first line differs (role, user, time). Sizes need no privilege, so nothing is hidden. The standby capture is from kes-node2, the kbdiag_ro one from kes-node1.

Exit codes

CodeMeaning
0OK
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.16 - table: one table

One table: size, rows, vacuum and analyze, freeze age, access, indexes.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Two WARN/OK examples were created by injection scripts: public.kbdiag_inj_dead (table with autovacuum_enabled=off, 10000 rows inserted and 5000 deleted) and public.kbdiag_inj_tbl (20000 rows inserted, 5000 deleted, with a primary key and a second index). Values belong to this capture only.

Usage

kbdiag table <name> [--json]

<name> follows SQL rules: it is resolved with to_regclass (as a bound parameter), so an unquoted name folds to lower case and is found through the search_path, the same as in ksql. Quote it as in SQL for upper case: '"Name"'. Connection options are the same as for sessions and it looks at the database you are connected to (use -d for another).

An empty name is a usage error (exit code 64). A name that cannot be found is UNKNOWN (3), not a usage error, because the table may live in another database.

A table on the primary

~/kbdiag table orders
echo EXIT_CODE=$?
table  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:57+08:00)

public.orders  (table)
  size        170 MB  (heap 62 MB, indexes 108 MB, no TOAST)
  rows        1000000 estimated; 1000000 live, 0 dead
  xid age     994  (autovacuum_freeze_max_age 200000000)
  mxid age    0
  reloptions  -

vacuum and analyze
  dead tuples             0, autovacuum threshold 200050
  last vacuum             9d 1h ago  (2 times)
  last autovacuum         never  (0 times)
  last analyze            9d 1h ago  (2 times)
  last autoanalyze        never  (0 times)
  modified since analyze  0

access since the statistics reset
  seq scans     21  (10000000 rows read)
  index scans   0  (0 rows fetched)
  rows written  0 inserted, 0 updated (0 HOT), 0 deleted
  heap blocks   23694 read, 108762 hit (82.1% hit)
  index blocks  6635 read, 10 hit (0.1% hit)

indexes: 3
  name                    size   scans  kind         definition
  idx_orders_user_status  30 MB  0      -            CREATE INDEX idx_orders_user_status ON public.orders USING btree (user_id, status)
  kbdiag_rev_idx          56 MB  0      -            CREATE INDEX kbdiag_rev_idx ON public.orders USING btree (md5((id)::text))
  orders_pkey             22 MB  0      primary key  CREATE UNIQUE INDEX orders_pkey ON public.orders USING btree (id)
EXIT_CODE=0
  • size is exact and split into heap, indexes and TOAST. It uses the same definition as top-objects, so the same table shows the same numbers on both. Resolving the name takes no lock, and the size is its own probe: if someone holds the table with VACUUM FULL, only the size is lost (after lock_timeout), the rest still shows, and the text points you to kbdiag locks.
  • rows has the estimate (reltuples) beside the live and dead tuples from the statistics. xid age is the freeze age against autovacuum_freeze_max_age.
  • vacuum and analyze: dead tuples against the autovacuum trigger line, the last manual and automatic vacuum and analyze with their counts, and the changes since the last analyze.
  • access since the statistics reset: scans, rows read and written, and block cache hits, one decimal place so that a few disk reads are not rounded to 100%.
  • indexes has size, scan count, whether it is the primary key, and the definition.
  • The judgment is the same as in the other commands, not a new rule: the age against the same two lines as freeze (finding id freeze.table_age), and a table with autovacuum off that is past its line as vacuum.table_disabled. Neither fires here, so it is OK.

The same table on the standby

~/kbdiag table orders
echo EXIT_CODE=$?
table  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:04+08:00)

public.orders  (table)
  size        170 MB  (heap 62 MB, indexes 108 MB, no TOAST)
  rows        1000000 estimated
  xid age     994  (autovacuum_freeze_max_age 200000000)
  mxid age    0
  reloptions  -

statistics: not_applicable  (standby: table statistics are local to each node and stay 0 here; run on the primary)

indexes: 3
  name                    size   scans  kind         definition
  idx_orders_user_status  30 MB  -      -            CREATE INDEX idx_orders_user_status ON public.orders USING btree (user_id, status)
  kbdiag_rev_idx          56 MB  -      -            CREATE INDEX kbdiag_rev_idx ON public.orders USING btree (md5((id)::text))
  orders_pkey             22 MB  -      primary key  CREATE UNIQUE INDEX orders_pkey ON public.orders USING btree (id)
EXIT_CODE=0

Table statistics are local to each node, so statistics is not_applicable and the index scan counts are - (NULL, not 0). The size, row estimate and age are replicated and still shown, and the age is still judged.

A table with autovacuum off

~/kbdiag table kbdiag_inj_dead
echo EXIT_CODE=$?
table  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:13+08:00)

[WARN] vacuum.table_disabled  table public.kbdiag_inj_dead has 5000 dead tuples, past its autovacuum threshold 2050, but autovacuum is off for it (autovacuum_enabled=off): nothing will clean it
  fix: VACUUM public.kbdiag_inj_dead  # connected to database test; turn autovacuum back on with ALTER TABLE ... RESET (autovacuum_enabled) unless it was turned off on purpose

public.kbdiag_inj_dead  (table)
  size        712 kB  (heap 704 kB, indexes 0 bytes, TOAST 8192 bytes)
  rows        10000 estimated; 5000 live, 5000 dead
  xid age     4  (autovacuum_freeze_max_age 200000000)
  mxid age    0
  reloptions  autovacuum_enabled=off

vacuum and analyze
  dead tuples             5000, autovacuum threshold 2050: due (autovacuum is off for this table)
  last vacuum             never  (0 times)
  last autovacuum         never  (0 times)
  last analyze            1s ago  (1 time)
  last autoanalyze        never  (0 times)
  modified since analyze  5000

access since the statistics reset
  seq scans     1  (10000 rows read)
  index scans   -
  rows written  10000 inserted, 0 updated (0 HOT), 5000 deleted
  heap blocks   87 read, 15335 hit (99.4% hit)
  index blocks  -

indexes: 0
EXIT_CODE=1
  • The finding is the same one kbdiag vacuum raises for this table: vacuum.table_disabled, with the same fix. reloptions shows the cause, autovacuum_enabled=off, and the text says due (autovacuum is off for this table).
  • modified since analyze is 5000, matching the 5000 deleted rows.

A table past its line with autovacuum on

~/kbdiag table kbdiag_inj_tbl
echo EXIT_CODE=$?
table  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:18+08:00)

public.kbdiag_inj_tbl  (table)
  size        2504 kB  (heap 1520 kB, indexes 976 kB, TOAST 8192 bytes)
  rows        20000 estimated; 15000 live, 5000 dead
  xid age     5  (autovacuum_freeze_max_age 200000000)
  mxid age    0
  reloptions  -

vacuum and analyze
  dead tuples             5000, autovacuum threshold 4050: due
  last vacuum             never  (0 times)
  last autovacuum         never  (0 times)
  last analyze            1s ago  (1 time)
  last autoanalyze        never  (0 times)
  modified since analyze  5000

access since the statistics reset
  seq scans     3  (20000 rows read)
  index scans   0  (0 rows fetched)
  rows written  20000 inserted, 0 updated (0 HOT), 5000 deleted
  heap blocks   189 read, 25743 hit (99.2% hit)
  index blocks  122 read, 79374 hit (99.8% hit)

indexes: 2
  name                 size    scans  kind         definition
  kbdiag_inj_tbl_n     520 kB  0      -            CREATE INDEX kbdiag_inj_tbl_n ON public.kbdiag_inj_tbl USING btree (n)
  kbdiag_inj_tbl_pkey  456 kB  0      primary key  CREATE UNIQUE INDEX kbdiag_inj_tbl_pkey ON public.kbdiag_inj_tbl USING btree (id)
EXIT_CODE=0

5000 dead tuples against a threshold of 4050, so it says due, but autovacuum is on for this table, so the next autovacuum round will take it: no finding, verdict OK.

A table that does not exist

~/kbdiag table no_such_table
echo EXIT_CODE=$?
kbdiag: no table "no_such_table" in database "test" (unquoted names fold to lower case; quote them as in SQL: '"Name"'; use -d for another database)
table  UNKNOWN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:19+08:00)

table: not found
EXIT_CODE=3

The first line is stderr. It says that unquoted names fold to lower case and that -d selects another database. Exit code 3 (UNKNOWN), and the report body only has table: not found.

Exit codes

CodeMeaning
0OK
1WARN: freeze.table_age past autovacuum_freeze_max_age, or vacuum.table_disabled (autovacuum off and past its line)
2FAIL: freeze.table_age at the stop limit (not produced in the lab)
3UNKNOWN: data not collected, or the table was not found
64Usage error, including an empty name
69Cannot connect

Back to the manual

5.17 - top: cumulative top SQL

Cumulative top SQL from sys_stat_statements; says so when statements are not being collected.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Nothing was injected. In the lab sys_stat_statements.track is none on both nodes, so statements are not being collected and top has no rows to show. This page shows that case, which is what the lab really looks like. The case with statistics on was not captured (see the last section).

Usage

kbdiag top [--limit N] [--by time|mean|calls|io|temp] [--json]
OptionEffect
--limit NShow at most N statements; default 20, 0 for all
--by ORDERSort by time (total execution time, the default), mean (time per call), calls, io (blocks read) or temp (temp blocks written). It is a sort, not a filter
--jsonPrint JSON

Anything else for --by is a usage error (exit code 64). Connection options are the same as for sessions.

Statements not being collected

~/kbdiag top
echo EXIT_CODE=$?
top  UNKNOWN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:58+08:00)

statements: skipped  (sys_stat_statements.track=none: statements are not being collected; set it to top or all)
EXIT_CODE=3
  • skipped with the reason written out, and the verdict is UNKNOWN: an empty table with an OK would claim “no expensive SQL” when nothing was measured. The standby (kes-node2) prints the same.
  • The switch to turn it on is sys_stat_statements.track (top or all). Two other reasons get their own text: the library is not in shared_preload_libraries (needs a restart), or the extension is not installed in this database (CREATE EXTENSION sys_stat_statements, or use -d).
  • The view is read from the schema where sys_extension says the extension lives, not through the search_path: a view of the same name in public could otherwise feed kbdiag false numbers.
  • This connection’s track=none does not by itself mean no data (a role or database can set it, and save=on keeps old data), so kbdiag reads the view anyway and writes skipped only when there is no row at all.

With statistics on: not captured

Taken from the source, not captured: with statements collected, the output is a table with the columns total, share, calls, mean, rows, read, temp, user, database and query, under a header that says the numbers are cumulative since the last reset.

  • share is the statement’s part of all execution time, the direct answer to “where does the database’s time go”. Which SQL is too expensive has no objective line, so top only shows and has no findings.
  • The numbers are cumulative since the last statistics reset. This version has no sys_stat_statements_info, so the reset time cannot be read, and the header says so. read and temp are blocks.
  • With track=all, statements run inside functions count again inside their callers, so the shares add up to more than 100%, and the text says so. With track=none and rows present, it says they were collected earlier, or for roles and databases that set track themselves.
  • Times use the unit that fits the size (0.09 ms, 503 ms, 1.75 s). A query that this account may not see is ?.
  • top --interval (the last N seconds) is not part of this version.

Exit codes

CodeMeaning
0OK: statements collected
3UNKNOWN: data not collected or not visible
64Usage error, including an invalid --by
69Cannot connect

Back to the manual

5.18 - progress: long operations

How far running VACUUM, CREATE INDEX, CLUSTER / VACUUM FULL and CHECKPOINT have got.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. The running example was created by an injection script that ran CREATE INDEX on public.orders (1,000,000 rows) and was read three times while it ran, once by kbdiag_ro. PIDs and timings belong to this capture only.

Usage

kbdiag progress [--json]

No options of its own. Connection options are the same as for sessions.

Nothing running

~/kbdiag progress
echo EXIT_CODE=$?
progress  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:58+08:00)

running: 0  (VACUUM, CREATE INDEX, CLUSTER and VACUUM FULL, CHECKPOINT; ANALYZE and base backups have no progress view in this version)
EXIT_CODE=0

The text says which operations it looks at. It also says what it cannot: ANALYZE and base backups have no progress view in this version. The standby (kes-node2) printed the same line.

  • kbdiag merges three PostgreSQL progress views (VACUUM, CREATE INDEX, CLUSTER / VACUUM FULL) into one probe, since the reader asks “how far is the long operation” and does not care which view it is in. KingbaseES’s own checkpoint view is a separate probe, because only its column names were observed and a failure there must not take the other three with it.

CREATE INDEX in progress

~/kbdiag progress
echo EXIT_CODE=$?
progress  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:24+08:00)

running: 1
  pid    command       database  relation  phase                           progress                  running
  43243  CREATE INDEX  test      orders    building index: scanning table  5058 / 7896 blocks (64%)  3s
EXIT_CODE=0

A few seconds later the same build:

~/kbdiag progress
echo EXIT_CODE=$?
progress  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:29+08:00)

running: 1
  pid    command       database  relation  phase                           progress                   running
  43243  CREATE INDEX  test      orders    building index: scanning table  7896 / 7896 blocks (100%)  8s
EXIT_CODE=0
  • phase is the operation’s own phase, and progress is done / total with its unit and a percentage. The counter is chosen by phase: block counts stop at the end of the scan, and the following phases (vacuum’s cleanup, the index’s sort and load) count something else, otherwise the display would sit at 100% for a long time. 100% in the second capture is the end of the table scan, not of the index build.
  • running is how long the operation has been running.
  • It only shows. How long is slow has no objective line, and whether a vacuum should run is judged by kbdiag vacuum. When a CREATE INDEX CONCURRENTLY is still waiting for other transactions, the phase is followed by how many are left and the text points to kbdiag locks, which is the usual reason it looks stuck.

Without privileges

kbdiag_ro (no monitoring role, over 127.0.0.1) reads the same build:

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro progress
echo EXIT_CODE=$?
progress  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-10-07T17:21:25+08:00)

running: 1
  pid    command                  database  relation  phase  progress  running
  43243  CREATE INDEX or REINDEX  test      -         ?      ?         ?
redacted: 1 row of progress.list hides phase (insufficient_privilege; grant sys_monitor)
EXIT_CODE=3

The operation is visible, but phase is hidden (?), so progress, running time and relation are not shown, and the label reads CREATE INDEX or REINDEX. The hidden cells are recorded under redacted. Because something could not be seen, the verdict is UNKNOWN even though the operation was found. Granting sys_monitor lifts it.

Exit codes

CodeMeaning
0OK
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.19 - checkpoint: checkpoint activity

The last checkpoint, timed vs requested checkpoints, who writes dirty buffers, and the settings.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Nothing was injected. Values belong to this capture only.

Usage

kbdiag checkpoint [--json]

No options of its own. Connection options are the same as for sessions.

Primary

~/kbdiag checkpoint
echo EXIT_CODE=$?
checkpoint  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:59+08:00)

last checkpoint
  time  2026-10-07 17:18:33  (2m 26s ago)
  redo  0/C651C548  (0000000300000000000000C6)

since the statistics reset 2026-09-15 23:12:34 (21d 18h ago)
  checkpoints        1606: 1606 timed, 0 requested (0%; requested covers WAL volume, CHECKPOINT, base backups, promotion)
  write, sync time   6m 54s, 490 ms
  buffers written    17029: checkpointer 10565 (62%), bgwriter 0 (0%), backends and others 6464 (38%)
  buffers allocated  37300
  backend fsyncs     0
  bgwriter stopped   0 times at bgwriter_lru_maxpages

settings
  checkpoint_timeout            5m 0s
  max_wal_size                  1024 MB
  checkpoint_completion_target  0.5
  checkpoint_warning            30s
  log_checkpoints               on
EXIT_CODE=0
  • last checkpoint is the time and the redo position (with its WAL file) of the latest checkpoint.
  • checkpoints counts timed and requested checkpoints since the statistics reset. “Requested” is not only WAL volume: a manual CHECKPOINT, a base backup (including a repmgr clone), a promotion, and creating or dropping a database count too. kbdiag gives the share but draws no conclusion. The server’s own “checkpoints too frequent” warning looks at the interval between two checkpoints (checkpoint_warning), which cumulative counters cannot give.
  • buffers written splits dirty-buffer writes into three: the checkpointer, the background writer, and “backends and others”. The third is not “the checkpointer cannot keep up”: in PG12 buffers_backend also counts relation extension, the ring buffers of VACUUM and COPY, and the standby’s startup process, so an idle node can show 60-70% there (65% and 70% were measured in this lab).
  • backend fsyncs above 0 is shown, not reported as a WARN. It means an fsync request could not be handed to the checkpointer, which happens when the queue is full or the checkpointer was not running at that moment (9 was measured earlier on this lab’s node2, which kbha had restarted).
  • settings is the relevant parameters.
  • Display only, so any probe that is not collected makes the verdict UNKNOWN; OK means “all collected”, not “good numbers”.

Standby

~/kbdiag checkpoint
echo EXIT_CODE=$?
checkpoint  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:06+08:00)

checkpoint record the last restartpoint started from (written by the primary)
  time  2026-10-07 17:18:33  (2m 33s ago)
  redo  0/C651C548  (0000000300000000000000C6)

since the statistics reset 2026-10-07 16:49:26 (31m 40s ago)
  checkpoints        43 timed, 0 requested restartpoint attempts (a standby counts every try, one every 15s while no new checkpoint record has arrived)
  write, sync time   2m 51s, 26 ms
  buffers written    45117: checkpointer 7496 (17%), bgwriter 0 (0%), backends and others 37621 (83%)
  buffers allocated  38458
  backend fsyncs     1
  bgwriter stopped   0 times at bgwriter_lru_maxpages

settings
  checkpoint_timeout            5m 0s
  max_wal_size                  1024 MB
  checkpoint_completion_target  0.5
  checkpoint_warning            30s
  log_checkpoints               on
EXIT_CODE=0
  • On a standby these are not restartpoint counts. In PG12 the checkpointer adds one for every attempt, and with no new checkpoint record it tries every 15 seconds (over four days that was 15917 attempts on this lab’s node2), so the text says restartpoint attempts and gives no ratio.
  • The header says the checkpoint record the last restartpoint started from was written by the primary: the time is the primary’s.

Exit codes

CodeMeaning
0OK
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.20 - wal: WAL position and what keeps it

Where WAL is, how much sys_wal holds, and what keeps it: settings, slots, archiving.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. Nothing was injected. Values belong to this capture only.

Usage

kbdiag wal [--json]

No options of its own. Connection options are the same as for sessions.

Primary

~/kbdiag wal
echo EXIT_CODE=$?
wal  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:20:59+08:00)

position
  lsn   0/C9352468
  file  0000000300000000000000C9

sys_wal: 214 files, 3248 MB

what keeps WAL here
  max_wal_size        1024 MB
  wal_keep_segments   8192 MB  (512 x 16 MB)
  slot repmgr_slot_2  0 bytes  (active)
  archiving           38 .ready files waiting  (kbdiag archive)
EXIT_CODE=0
  • position is the current write position and its WAL file.
  • sys_wal is the same size as on space: same probe, same columns.
  • what keeps WAL here puts on one screen what you would otherwise assemble from three commands: the parameters (max_wal_size, wal_keep_segments as its size), each replication slot with the WAL it retains and whether it is active, and the archive backlog. Here the slot retains 0 bytes and is active, but 38 .ready files wait for archiving (the lab’s archiving is failing, see archive).
  • It shows and does not repeat the judgment. An inactive slot is reported by kbdiag slots and a failing archive by kbdiag archive; this screen only points there. The same problem reported in three commands would look like three problems.
  • The WAL generation rate needs two samples over time; a single query cannot give it, so this version does not.

Standby

~/kbdiag wal
echo EXIT_CODE=$?
wal  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:06+08:00)

position
  replayed  0/C9352A80

sys_wal: 198 files, 3136 MB

what keeps WAL here
  max_wal_size       1024 MB
  wal_keep_segments  8192 MB  (512 x 16 MB)
  slots              none
  archiving          0 .ready files waiting
EXIT_CODE=0

On a standby position is the replay position (there is no write position, and no WAL file name). This standby has no slots of its own, and nothing waits for archiving.

Exit codes

CodeMeaning
0OK
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual

5.21 - seq: sequences

Sequences of this database by how much of their range is used; FAIL when one is exhausted.

Captured on 2026-10-07 (UTC+08) on a local KingbaseES V008R006C009B0014 primary and standby, database test, using ~/kbdiag built from Go source commit 96c874f (static linux/amd64 binary). This is lab evidence, not production validation. The FAIL example was created by an injection script: it created public.kbdiag_inj_seq with maxvalue 3 and used it up with nextval. Values belong to this capture only.

Usage

kbdiag seq [--limit N] [--json]
OptionEffect
--limit NShow at most N sequences; default 20, 0 for all
--jsonPrint JSON

Connection options are the same as for sessions and it looks at the database you are connected to. --limit only trims the list; the finding covers every sequence.

Primary

~/kbdiag seq
echo EXIT_CODE=$?
seq  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:00+08:00)

sequences in test: 16, most used first
  sequence                                type     last     limit                used   left
  public.kbdiag_test_id_seq               integer  1311000  2147483647           0.06%  2.15e+09
  kdb_schedule.kdb_jobclass_jclid_seq     integer  5        2147483647           0.00%  2.15e+09
  perf.kwr_snapshots_snap_id_seq          integer  2        2147483647           0.00%  2.15e+09
  public.flight_psg_new_info_id_seq       bigint   1000000  9223372036854775807  0.00%  9.22e+18
  public.orders_id_seq                    bigint   1000000  9223372036854775807  0.00%  9.22e+18
  public.t_perf_test_id_seq               bigint   100000   9223372036854775807  0.00%  9.22e+18
  sysmac.sysmac_policy_oid_seq            bigint   1        9223372036854775807  0.00%  9.22e+18
  kdb_schedule.kdb_action_acid_seq        integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_exception_jexid_seq    integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_job_action_jaid_seq    integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_joblog_jlgid_seq       integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_jobsteplog_jslid_seq   integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_schedule_job_sjid_seq  integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_schedule_scid_seq      integer  -        2147483647           -      no value yet
  sys_catalog.global_chain_seq            bigint   -        9223372036854775807  -      no value yet
  sys_hm.hm_run_t_run_id_seq              integer  -        2147483647           -      no value yet
EXIT_CODE=0
  • The sequences are ordered by how much of their range is used. last is the last value handed out, limit the end of the range it counts toward (its own MAXVALUE, or MINVALUE for a descending one), used the share, left how many values remain. The arithmetic is exact (math/big), since a bigint sequence spans the whole int64 range and plain subtraction would overflow.
  • A sequence that has never been called, or was reset with setval(..., false), has no last value: it is shown as no value yet, with -.
  • Only one thing is judged: seq.exhausted (FAIL), when nextval already fails. A sequence that merely runs low is shown, not reported: how low is too low has no objective line. A sequence that cycles does not count as used up; it would be written as cycles (not captured in the lab).

Standby

~/kbdiag seq
echo EXIT_CODE=$?
seq  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:07+08:00)

sequences in test: 16, most used first
  on a standby a sequence reads up to 32 values ahead of the primary (and is not judged): run on the primary
  sequence                                type     last     limit                used   left
  public.kbdiag_test_id_seq               integer  1311029  2147483647           0.06%  2.15e+09
  kdb_schedule.kdb_jobclass_jclid_seq     integer  33       2147483647           0.00%  2.15e+09
  perf.kwr_snapshots_snap_id_seq          integer  33       2147483647           0.00%  2.15e+09
  public.flight_psg_new_info_id_seq       bigint   1000032  9223372036854775807  0.00%  9.22e+18
  public.orders_id_seq                    bigint   1000032  9223372036854775807  0.00%  9.22e+18
  public.t_perf_test_id_seq               bigint   100023   9223372036854775807  0.00%  9.22e+18
  sysmac.sysmac_policy_oid_seq            bigint   1        9223372036854775807  0.00%  9.22e+18
  kdb_schedule.kdb_action_acid_seq        integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_exception_jexid_seq    integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_job_action_jaid_seq    integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_joblog_jlgid_seq       integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_jobsteplog_jslid_seq   integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_schedule_job_sjid_seq  integer  -        2147483647           -      no value yet
  kdb_schedule.kdb_schedule_scid_seq      integer  -        2147483647           -      no value yet
  sys_catalog.global_chain_seq            bigint   -        9223372036854775807  -      no value yet
  sys_hm.hm_run_t_run_id_seq              integer  -        2147483647           -      no value yet
EXIT_CODE=0

A standby’s sequence value is the copy in the WAL, and the primary writes 32 values ahead each time, so a standby can read “at the end” while the primary still has values. The text says so (up to 32 values ahead of the primary), and the standby is not judged: run seq on the primary. The last values above are indeed larger than the primary’s.

Without privileges

kbdiag_ro (no monitoring role, over 127.0.0.1):

PGPASSWORD=... ~/kbdiag --host 127.0.0.1 -U kbdiag_ro seq
echo EXIT_CODE=$?
seq  UNKNOWN  (KingbaseES V008R006C009B0014, primary, kbdiag_ro@remote, 2026-10-07T17:21:08+08:00)

sequences in test: 16, most used first
  sequence                                type     last  limit                used  left
  kdb_schedule.kdb_action_acid_seq        integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_exception_jexid_seq    integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_job_action_jaid_seq    integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_jobclass_jclid_seq     integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_joblog_jlgid_seq       integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_jobsteplog_jslid_seq   integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_schedule_job_sjid_seq  integer  ?     2147483647           ?     ?
  kdb_schedule.kdb_schedule_scid_seq      integer  ?     2147483647           ?     ?
  perf.kwr_snapshots_snap_id_seq          integer  ?     2147483647           ?     ?
  public.flight_psg_new_info_id_seq       bigint   ?     9223372036854775807  ?     ?
  public.kbdiag_test_id_seq               integer  ?     2147483647           ?     ?
  public.orders_id_seq                    bigint   ?     9223372036854775807  ?     ?
  public.t_perf_test_id_seq               bigint   ?     9223372036854775807  ?     ?
  sys_catalog.global_chain_seq            bigint   -     9223372036854775807  -     no value yet
  sys_hm.hm_run_t_run_id_seq              integer  -     2147483647           -     no value yet
  sysmac.sysmac_policy_oid_seq            bigint   ?     9223372036854775807  ?     ?
redacted: 14 rows of seq.list hide last_value (insufficient_privilege; grant SELECT on the sequences (sys_monitor does not cover them))
EXIT_CODE=3
  • ? is a last_value this account may not read (no SELECT on the sequence), so used and left cannot be computed. The SQL checks the privilege by oid, so a sequence dropped meanwhile does not fail the whole probe. The 14 hidden rows are in redacted, with the advice to grant SELECT on the sequences: sys_monitor does not cover them.
  • The two rows with - are sequences never called (no value yet): that is not the same NULL as a privilege gap, and kbdiag keeps the two apart.
  • The verdict is UNKNOWN, because it could not see the values.

An exhausted sequence

~/kbdiag seq
echo EXIT_CODE=$?
seq  FAIL  (KingbaseES V008R006C009B0014, primary, system@local, 2026-10-07T17:21:20+08:00)

[FAIL] seq.exhausted  sequence public.kbdiag_inj_seq (integer) is at 3, its limit is 3: nextval fails, so inserts that use it fail
  fix: ALTER SEQUENCE public.kbdiag_inj_seq MAXVALUE <higher>  # it stops at its MAXVALUE, short of what its type allows

sequences in test: 17, most used first
  sequence                                type     last     limit                used     left
  public.kbdiag_inj_seq                   integer  3        3                    100.00%  0
  public.kbdiag_test_id_seq               integer  1311000  2147483647           0.06%    2.15e+09
  kdb_schedule.kdb_jobclass_jclid_seq     integer  5        2147483647           0.00%    2.15e+09
  perf.kwr_snapshots_snap_id_seq          integer  2        2147483647           0.00%    2.15e+09
  public.flight_psg_new_info_id_seq       bigint   1000000  9223372036854775807  0.00%    9.22e+18
  public.orders_id_seq                    bigint   1000000  9223372036854775807  0.00%    9.22e+18
  public.t_perf_test_id_seq               bigint   100000   9223372036854775807  0.00%    9.22e+18
  sysmac.sysmac_policy_oid_seq            bigint   1        9223372036854775807  0.00%    9.22e+18
  kdb_schedule.kdb_action_acid_seq        integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_exception_jexid_seq    integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_job_action_jaid_seq    integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_joblog_jlgid_seq       integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_jobsteplog_jslid_seq   integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_schedule_job_sjid_seq  integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_schedule_scid_seq      integer  -        2147483647           -        no value yet
  sys_catalog.global_chain_seq            bigint   -        9223372036854775807  -        no value yet
  sys_hm.hm_run_t_run_id_seq              integer  -        2147483647           -        no value yet
EXIT_CODE=2
  • seq.exhausted is a FAIL: nextval fails, so inserts that use it already fail. The line is the sequence’s own limit, so there is no option for it.
  • The fix depends on what blocks it. Here the sequence stops at its own MAXVALUE 3, short of what integer allows, so it raises that. When the sequence is at the limit of its type, an int or smallint becomes bigint (change the column first; this rewrites the table), and a bigint has no remedy but a new key. A sequence with a mismatched bigint sequence on an int column, where the column overflows first, is not detected.

The same database on the standby:

~/kbdiag seq
echo EXIT_CODE=$?
seq  OK  (KingbaseES V008R006C009B0014, standby, system@local, 2026-10-07T17:21:21+08:00)

sequences in test: 17, most used first
  on a standby a sequence reads up to 32 values ahead of the primary (and is not judged): run on the primary
  sequence                                type     last     limit                used     left
  public.kbdiag_inj_seq                   integer  3        3                    100.00%  0
  public.kbdiag_test_id_seq               integer  1311029  2147483647           0.06%    2.15e+09
  kdb_schedule.kdb_jobclass_jclid_seq     integer  33       2147483647           0.00%    2.15e+09
  perf.kwr_snapshots_snap_id_seq          integer  33       2147483647           0.00%    2.15e+09
  public.flight_psg_new_info_id_seq       bigint   1000032  9223372036854775807  0.00%    9.22e+18
  public.orders_id_seq                    bigint   1000032  9223372036854775807  0.00%    9.22e+18
  public.t_perf_test_id_seq               bigint   100023   9223372036854775807  0.00%    9.22e+18
  sysmac.sysmac_policy_oid_seq            bigint   1        9223372036854775807  0.00%    9.22e+18
  kdb_schedule.kdb_action_acid_seq        integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_exception_jexid_seq    integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_job_action_jaid_seq    integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_joblog_jlgid_seq       integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_jobsteplog_jslid_seq   integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_schedule_job_sjid_seq  integer  -        2147483647           -        no value yet
  kdb_schedule.kdb_schedule_scid_seq      integer  -        2147483647           -        no value yet
  sys_catalog.global_chain_seq            bigint   -        9223372036854775807  -        no value yet
  sys_hm.hm_run_t_run_id_seq              integer  -        2147483647           -        no value yet
EXIT_CODE=0

Same 100.00% row, and the standby still says OK because it does not judge sequences.

Exit codes

CodeMeaning
0OK
2FAIL: a sequence cannot hand out another value
3UNKNOWN: data not collected or not visible
64Usage error
69Cannot connect

Back to the manual