Skip to content

Stateless requests mean there is no session to count

Active connections are absent rather than zero and no connection ceiling is published, while table and index bytes are real because the storage view answers.

Open the monitoring dashboard on a libSQL connection and several tiles have nothing in them. That is the correct reading. A checklist written against a connection-pooled engine - uptime, active connections, a cache hit ratio, a slow query log - misses on almost every line here, and every miss traces back to one protocol decision made above the storage layer.

libSQL is SQLite’s dialect with a server in front of it. The server is sqld, and what sqld speaks is Hrana: a list of requests posted as JSON to POST /v2/pipeline, one result per request. One type-id, libsql, reaches both a self-hosted sqld and Turso Cloud, because they speak that same protocol and embed the same SQLite - 3.47.0 measured on both, on 2026-08-27. There is no driver dependency of any kind; the whole transport is about 330 lines, and a statement travels through the runtime’s own fetch.

One statement, one request, no session

A pooled engine gives a monitoring dashboard its spine for free. A session exists, it has a start time, a state and a current statement, so the server can be asked to list them. Hrana has no session object. A statement is a request, the stream closes with it, and the next statement is a new request. This provider holds nothing between the two.

That is also why transaction controls are hidden on this engine rather than shown and then failed. libSQL has transactions; the provider closes its Hrana stream in the same request as the statement, so it holds no session to carry one. supportsTransactions is false and the controls do not render. The same fact drives everything below.

What is absent, and why zero would be wrong

Here is the monitoring surface as it was measured through the product against both deployments, with a fixture of two tables - 3 rows and 2000 rows - and one index.

Panel Reading
Uptime N/A - no route or catalog publishes one
Max connections 0, this codebase’s encoding for “no limit published”
Active connections absent - Hrana is stateless
Cache hit ratio N/A - SQLite’s counters sit behind the C API, and no statement reaches them
Active sessions empty - no session exists to report
Slow queries empty, permanently - libSQL keeps no statistics about finished statements
Deadlocks 0
Health Integrity: OK, Journal Mode: wal

Two rows in that table are doing more work than the others.

Active connections is absent, not zero. getActiveSessions() answers [], and the tile renders no number at all. A 1 there would be the provider counting the request it is making to ask the question - the dashboard describing itself. A 0 would be a claim about the server that nobody measured. Absence is the only honest reading, and the same rule governs the byte fields further down: where a figure is unavailable it is omitted, because 0 B next to a table name reads as an empty table.

Deadlocks is a fact rather than a gap. SQLite serialises writers behind one write lock and refuses a second with SQLITE_BUSY, so 0 there is the engine’s behaviour written down, not a counter that failed to load. That distinction is why what each panel can show is bounded by what the engine reports rather than by a shared layout, which is the trade the interface makes on every engine.

State the boundary plainly, because it is the shape of this engine and not a defect: uptime is N/A, active connections are absent because each statement is its own stateless HTTP request, no connection ceiling is published, and vacuum, analyze and checkpoint are refused by the server’s own statement allowlist. Nothing on this page is waiting for a later release to fill it in.

The version each deployment publishes

GET /version is a sqld route. Turso Cloud does not have it and answers {"error":"route not found: [\"version\"]"}, so serverVersion() returns null there instead of throwing. The panel then reads what each deployment actually published:

  • self-hosted: sqld 0.24.33 (f8fb14f3 2026-08-11) (SQLite 3.47.0)
  • Turso Cloud: SQLite 3.47.0

Neither reads “Unknown”, because in both cases the engine answered something. The Cloud string is shorter because one route is missing, not because the reading failed, and a dashboard that cannot tell those two apart teaches you to ignore it.

Those version strings are dated measurements against one build and one Turso Cloud database, re-probed on the pinned v0.24.33 image. They are not a supported range.

Where the real byte figures come from

Two figures on this dashboard are measured rather than estimated: the bytes a table occupies and the bytes its indexes occupy.

Introspection here is plain SQL: sqlite_master for tables, the pragma_table_info, pragma_index_list, pragma_index_info and pragma_foreign_key_list functions for structure, and dbstat for bytes.

SELECT name, SUM(pgsize) AS bytes FROM dbstat GROUP BY name

dbstat answers on both deployments. Against the fixture that produced 4096 bytes of table and 4096 of index for the 3-row table, and 53248 bytes for the 2000-row one; the database size tile read 64 KB, 65536 bytes, from page_count x page_size. Row counts are a real SELECT COUNT(*) per table rather than a statistics estimate. The index panel lists idx_customers_country with its column and its 4096 bytes and reports scans: 0, because no per-index scan counter exists to read.

The Storage tab shows one entry, main, at 65536 bytes, and no WAL size. No statement reports the WAL, and the pragma that would checkpoint it is refused. So the tab is one row, and the missing row has a reason printed where it would have been.

A whole schema read is three round trips regardless of table count, plus one for sizes, because Hrana takes a list of requests and sends them together. A failing statement does not abort the pipeline, so outcomes come back per statement: one table’s column read can fail while every other table in the tree stays intact.

Maintenance the server itself refuses

The maintenance toolkit on this engine offers two operations, reindex and check. Measured on both deployments:

Statement Result
REINDEX accepted
PRAGMA integrity_check accepted
VACUUM refused
ANALYZE refused
PRAGMA optimize refused
PRAGMA wal_checkpoint(TRUNCATE) refused

The two deployments word the identical refusal differently under one error code, so nothing in the provider matches on the message text. runMaintenance refuses those types here rather than relaying a server error for a statement the user never typed, and the controls are withheld rather than drawn and failed. The maintenance toolkit and the audit trail are admin-only in any case.

PRAGMA query_only = true is on the same refused list, which is why agent AUTO mode ends engine-unsupported on libSQL: the read-only profile is enforced by the database, statement by statement, and there is no statement this provider can issue to establish one here. The engine-side answer exists and is a credential you create, turso db tokens create <database> --read-only. Agent plan mode opens on this connection like any other - toolless, executing nothing, drafting a statement for a human to run.

PRAGMA integrity_check is worth one more sentence, because its answer is read rather than its status. A corrupt database reports the damage in the returned row while the statement itself succeeds, so checking only for an error would report a healthy database.