Skip to content

On a Trino connection the database field is a catalog

Pinning a catalog scopes the whole tree two levels deep, and a connection that pins none still connects and runs fully qualified statements with no tree.

Trino stores nothing. Every table it can name belongs to a system behind a connector, and a deployment is a set of configured catalogs pointed at those systems. That one fact decides how you connect Trino - the catalog, the schema, and what the client sends on the wire - and it decides the shape of everything the sidebar can show you afterwards.

The field labelled Database on a Trino connection holds a catalog. Type a schema name into it and the symptom is not an error: the connection succeeds and the tree is either wrong or empty.

Connect Trino by catalog: what each field in the client means

There is no driver here. Statements go out as the body of an HTTP request to POST /v1/statement and the answer is read by following a chain of nextUri links, which is Trino’s own client protocol. The provider was verified against Apache Trino 476 (trinodb/trino:476), measured 2026-08-20.

Field Required What it does
Host Yes The coordinator. The only validated requirement
Port No Defaults to 8080, for both http:// and https://
Database No The catalog to pin. Without it the editor works and the tree does not
Username No Sent as X-Trino-User. Defaults to libredb, never omitted
Password No Authorization: Basic, and only over TLS
SSL No Selects https://

Two of those rows are worth reading twice. The port default is 8080 under TLS as well, because a secured cluster listens wherever its operator put it and inventing a well-known HTTPS port would send credentials to somewhere nothing is listening. And a password requires TLS: measured against a coordinator with authentication switched off entirely, an Authorization: Basic header over plain HTTP answers 401 Unauthorized with Password not allowed for insecure authentication. That is the server’s rule, so the transport constructor refuses the configuration up front rather than sending the credential and reporting the 401.

There is no connection string field on this form at all. jdbc:trino://host:port/catalog/schema is a real and widely pasted form, and the shared parser in src/lib/connection-string-parser.ts does not accept it. A field that would reject everything a user pastes into it is worse than no field, so supportsConnectionString is false and stays false until the parser learns the scheme. Fill the fields in individually.

There is also no field for a session schema, which matters in a moment.

Catalog, schema, table, and how the tree gets shaped

Trino’s hierarchy is catalog to schema to table, one level deeper than the tree’s database to schema to table. The mapping chosen is the PostgreSQL one: the connection’s database field holds the catalog, exactly as a PostgreSQL connection pins one database, and the schemas inside it become the schema level. So the tree is two levels deep, and a table’s display name is always schema.table.

Introspection is two statements run in parallel against the pinned catalog’s information_schema - the table list and the column list - both excluding information_schema itself, both ordered by ordinal_position so the mapper never sorts. Against tpch that is 72 tables.

The alternative, fanning information_schema out across every catalog on the cluster, is unbounded in practice. The jmx catalog alone publishes one table per MBean, and jmx.current measured 379. One sidebar refresh would then depend on every connector the operator has configured being reachable. SHOW CATALOGS is still useful and it is exposed where it belongs: the Storage panel reads system.metadata.catalogs and lists one row per catalog with its connector.

What the tree cannot show you is a key. Trino’s information_schema holds exactly eight views - applicable_roles, columns, enabled_roles, roles, schemata, table_privileges, tables and views - with no table_constraints and no key_column_usage, so no connector can declare a key through it. indexes and foreignKeys are [] by construction, isPrimary is false everywhere, and inline row editing is not offered, because an UPDATE ... WHERE with no column that identifies one row would rewrite every row that matches. That is a fact about the engine, not a gap in the client, and it is published on the engine pages rather than discovered at runtime.

A connection that pins no catalog

Leave the database field empty and the connection still works. It connects, it runs every fully qualified statement you type, and it reads the whole of system.runtime, which is where the overview, the session list and the slow query list come from. What it cannot do is show a tree, and getSchema() says so: This connection pins no Trino catalog, so there is no schema to list.

That is a usable connection, not a broken one. It is the right shape for a cluster where you work across catalogs all day and the tree for any single one of them would only be in the way. If you do want the tree, add the catalog and reconnect; the pin is the only thing that decides which catalog the sidebar reads.

For a local cluster to try this against, trinodb/trino:476 ships tpch, tpcds, memory, system and jmx already configured, so there is no seed step. Point a connection at localhost:8080 with no user, no password and tpch in the database field, and tpch.tiny.nation is there. The rest of the setup is in getting started.

Cross-catalog statements, fully qualified

Pinning a catalog constrains the tree and nothing else. The editor is untouched:

SELECT n.name, o.orderstatus, count(*) AS orders
FROM tpch.tiny.orders o
JOIN tpch.tiny.customer c ON c.custkey = o.custkey
JOIN memory.default.watchlist w ON w.custkey = c.custkey
JOIN tpch.tiny.nation n ON n.nationkey = c.nationkey
GROUP BY n.name, o.orderstatus

runs exactly as typed with tpch pinned, because the pinned catalog only supplies the default for names that are not fully qualified. Qualify in full and the pin never enters the resolution. (watchlist there is a table of your own on the memory connector, which is one of the connectors that accepts CREATE TABLE.)

Qualifying in full is also the habit to keep, because each statement is one stateless exchange of HTTP requests with no pooling and nothing carried between them. USE, SET SESSION, PREPARE and DEALLOCATE all report success and have no effect on the next statement, so each one attaches a warning saying that: succeeded, but each statement is sent on its own connection, so it will not affect the next one. Qualify names in full instead. This is the same reason there is no session schema field, and the reason generated names are always schema.table.

Two smaller grammar facts travel with this. Trino’s clause order is [OFFSET count] [LIMIT count] and only that way round - ... LIMIT 3 OFFSET 1 answers line 1:47: mismatched input 'OFFSET' - so paged reads transpose what the shared limiter emitted. And SELECT 1; is a syntax error, line 1:9: mismatched input ';', so the transport drops a single trailing semicolon before the statement leaves it.

Reading a failure that arrives as a success

A failed Trino statement arrives as HTTP 200 with the failure inside the document. SELEKT 1, a missing table and an unsupported DDL all answer 200. So the transport categorises from the body and never from the status, and the status is consulted for exactly one thing: a request the coordinator refused before it became a statement at all, which is the plain-HTTP password 401 above.

If you probe a cluster with curl before you connect the client, read the body and not the status. A 200 is not a result.

What the client does with the body is keep the engine’s own wording verbatim - line 1:15: Table 'tpch.tiny.nope' does not exist - because nothing synthesized locally locates the fault better, and carry the 1-based error location alongside it. What it drops at the seam is the Java stack: 19 frames and 3.3 KB for the simplest possible typo.

The same rule reads the other way when a statement fails because of the connector rather than the engine. CREATE TABLE is in the grammar and works on the memory connector; the same connector answers UPDATE with This connector does not support modifying table rows. That refusal is shown as the connector wrote it, not substituted for a sentence of ours, because the connector is the only thing that knows.