The Couchbase role your monitoring panels depend on
Without the query system catalog role, slow queries and sessions are empty and denied metrics are omitted rather than reported as zero.
You connect a Couchbase bucket, the tree fills in, statements run, and the monitoring dashboard opens with two panels blank and a third reading N/A. Nothing errored. The usual cause is neither the cluster nor the connection. It is the Query System Catalog role, and whether the account you connected with holds it.
That is deliberate. Without the Query System Catalog role slow queries and active sessions are empty, index scan counts read zero, and denied performance metrics are omitted rather than shown as zeroes, by design.
Which reads need the catalog role, and which do not
The monitoring dashboard on this engine is assembled from two different kinds of source, and they fail differently.
| Panel | Source | Needs the catalog role |
|---|---|---|
| Overview | /pools/default, /pools/default/buckets/<bucket>, system:keyspaces, system:indexes |
partly |
| Performance | bucket statistics series | no, but needs bucket stats |
| Slow queries | system:completed_requests ordered by elapsedTime |
yes |
| Sessions | system:active_requests |
yes |
| Tables | /pools/default/buckets/<bucket> |
no |
| Indexes | system:indexes plus /pools/default/buckets/@index-<bucket>/stats |
yes for the statistics |
| Storage | /pools/default/buckets/<bucket> |
no |
The split follows the source, not the panel. Three sources need the Query System
Catalog RBAC role: system:completed_requests, system:active_requests and the
index-service statistics. Everything else is gated by whatever bucket-level roles
the account holds, which is why an account can show you disk used and RAM quota
while showing you nothing at all about the queries that filled them. Not every
system: keyspace sits behind that door either - system:keyspaces and
system:indexes are not among the three, which is why the index list still
renders while its scan counts read zero.
Two gaps here have nothing to do with privileges. There is no Pool tab, because
there is no connection pooling: every statement is one stateless HTTP request to
the discovered query port. Table statistics are bucket level only, because a
per-collection item count needs a COUNT(*) per collection, too expensive for a
monitoring poll. Those two are architectural. The blank slow-query list is a
permission.
What a restricted user sees on the dashboard
A denial does not surface as an error, because a denial is the ordinary case. An application user is usually granted exactly the bucket access the application needs and nothing from the query catalog. Every monitoring read on this provider therefore funnels through one helper:
async function degradeTo<T>(operation: () => Promise<T>, fallback: T): Promise<T> {
try { return await operation(); } catch { return fallback; }
}
A source the connected user cannot read yields its fallback instead of breaking an otherwise working connection.
Concretely, on a restricted account: the slow-query list is [], the session
list is [], index rows still appear from system:indexes with their name,
scope, collection, keys and type, and their scan counts read 0. The overview
still reports version, uptime and active connections when the management reads
are allowed. maxConnections in that overview is the documented KV default,
65536, because Couchbase advertises no connection ceiling over REST - the
denominator is a constant while the numerator stays measured.
One consequence worth flagging: cancelling a running statement needs the role
too. This provider exposes no cancelQuery; a running request is terminated
through the maintenance kill operation, which is
DELETE FROM system:active_requests WHERE requestId = $1 and takes the request
id shown in the sessions panel. No sessions panel, no request id, no kill. The
maintenance toolkit and the audit trail are admin-only in any case, which is
described alongside the other access boundaries the deployment
publishes.
Omitted rather than zero, and the bug behind that rule
Three performance fields are optional on this provider, and each is left out when its source published nothing:
| Field | Reported when | Omitted when |
|---|---|---|
cacheHitRatio |
the ep_cache_miss_rate series has a numeric last sample |
the series is absent - the stats endpoint was denied, or the bucket publishes no ep_* series |
queriesPerSecond |
at least one of cmd_get / cmd_set was published |
neither was published |
bufferPoolUsage |
basicStats.quotaPercentUsed is a number |
basicStats is missing, meaning the bucket endpoint was unreadable |
A measured 0 is kept in every one of those cases. A bucket with no misses
really is at a 100% hit ratio, an idle bucket really is doing 0 operations, and
an empty bucket really is using none of its quota. The distinction the table is
drawing is between zero and unknown, and the reason it is drawn this hard is a
bug this provider shipped once.
The cache ratio used to fall back to 0 when the miss-rate series came back
null. The stand-in was chosen for a defensible reason: 100 would have been
flattering, and a flattering default on a metric nobody measured is worse than a
pessimistic one. But the health thresholds rate the cache hit ratio with
direction: "below" and critical: 80, so a 0 is not neutral - it is the worst
possible reading. Every bucket whose KV statistics the connected user was not
allowed to read rendered a red critical cache fault that the cluster had never
reported. Because reading those statistics needs a role many application users
lack, that was the common path, not an edge case.
The fix is the rule in the table above. Omitted, the same panels render N/A or
“Not measured” and score the card as healthy, so an operator can tell a failing
cache from a metric they have no permission to see. A stand-in destroys that
distinction in both directions: it invents an alert no system raised, and it
teaches the reader to ignore the next one.
The same reasoning shapes what the slow-query panel means when it does have data.
Rows come from system:completed_requests, one row per recorded request, so
calls is always 1. These are individual requests, not aggregates. If you are
looking for the statement that ran ten thousand times, this panel will not group
it for you, and it does not pretend to.
One deliberate exception to the degrade-to-empty rule
Degrading to empty is safe when empty is a meaningless value. It is not safe when empty already means something specific, and on Couchbase there is exactly one such read.
getSchemaRelations() reads the index catalog. An empty index list is not a
neutral result on this engine: it is the signal that a keyspace is un-indexed,
which changes how the collection reads. From Server 7.6 the query service falls
back to a sequential scan, so an un-indexed collection opens - verified on
Community Edition 8.0.2, where EXPLAIN shows the fallback explicitly:
{ "#operator": "PrimaryScan3", "index": "#sequentialscan", "using": "sequentialscan" }
On Server 7.0 to 7.2 the same statement fails with error 4000 instead.
So if a denied catalog read degraded to [] there, the interface would report
that every collection in the bucket is un-indexed, on the strength of having read
nothing. That is a fabricated finding, not a missing one, and it would send
someone to create indexes that already exist. The read is allowed to fail loudly
instead. One exception, written down where the rule is, for the one case where
the fallback value carries a claim of its own.
Sizes the server no longer publishes
The last gap on this dashboard is not a permission at all, and it is easy to mistake for one.
Per-index sizes came from /pools/default/buckets/@index-<bucket>/stats. Modern
servers no longer publish a per-index series there. When there is none, the index
row shows indexSize: "N/A" and indexSizeBytes is omitted entirely rather than
set to 0 - because a 0 B reads as an empty index, and the Storage tab summed
those zeroes into a total that was quietly wrong.
scans is the one field that still falls back to 0, and only because
IndexStats.scans is a required field on the shared type. Read a 0 there as
“not measured” unless you know the account holds the catalog role. That is the
one seam where the omission rule could not be applied, and it is stated here
rather than smoothed over - the same way the rest of the
capability model names what each engine cannot answer.