Connect a SQL client
OriginChain speaks the PostgreSQL wire protocol. You can point an ordinary Postgres client at your database and run SQL against the same data your HTTP API calls see - one store, one source of truth.
Wire-protocol access is in limited preview and is being enabled gradually. Self-serve enablement covers single-node instances for now - for HA or multi-node configurations, talk to us. If your instance doesn't show a SQL access panel in the console yet, the listener isn't switched on for you - everything on this page also works over the SQL endpoint of the HTTP API today. This page states plainly what works over the wire and what doesn't; the matrix below is the honest version, not the optimistic one.
What you can connect.
Any client or driver that speaks the PostgreSQL protocol can connect. The three we verify against are psql, DBeaver, and pgAdmin - walkthroughs for each are below. Language drivers that use the same protocol (libpq, JDBC's PostgreSQL driver, node-postgres, psycopg, pgx, and friends) connect the same way, and so does the standard PostgreSQL ODBC driver - DSN details below.
MySQL Workbench and SQL Server Management Studio (SSMS) cannot connect. They speak different wire protocols (the MySQL protocol and TDS respectively), not PostgreSQL's - no connection setting will make them work. Don't spend an afternoon on it; use one of the three clients above.
Connection details.
Host, port, username and password are per-database and live in the console: open your instance and look for the SQL access panel. The port is PostgreSQL's stock 5432; authentication is SCRAM-SHA-256 (the flow every current Postgres client speaks), and the connection must use TLS - keep sslmode=require.
host <your-database-host> # console -> your instance -> SQL access
port 5432 # PostgreSQL's stock port - the panel shows it too
database postgres # cosmetic - see the note below this block
user <user> # shown in the SQL access panel
password <password> # shown in the SQL access panel
sslmode require
# Or as one connection URI:
postgresql://<user>:<password>@<your-database-host>:5432/postgres?sslmode=require
Which database you connect to is decided by your credentials, not by the database field. The server reports a single database named postgres to every client, whatever you type there. Leave it as postgres so GUI clients resolve their navigation tree cleanly - but know that typing something else neither connects you elsewhere nor protects anything. (The console's connection string may name a different database - same cosmetic field, connects identically.)
One more gate before the first connect: the SQL port is reachable only from addresses on your instance's IP Access List - it is never open to the world. An empty list means the port stays closed and every client times out. Add the address you connect from (console → your instance → Network access) and retry.
Client walkthroughs.
Each tab is the short version: the fields that matter and the one gotcha worth knowing in advance. pgAdmin gets a fuller step-by-step just below, and ODBC consumers have a section of their own.
# One line - paste the values from the console's SQL access panel:
psql "host=<your-database-host> port=5432 dbname=postgres \
user=<user> password=<password> sslmode=require"
# Gotcha: \copy (and the COPY protocol generally) is not supported yet.
# Bulk-load with a multi-row INSERT ... VALUES (...), (...) instead,
# or use the HTTP ingest API. Everything else psql does day-to-day -
# queries, \d, \dt, \df, PREPARE/EXECUTE, transactions - works.1. New Database Connection -> PostgreSQL (the stock PostgreSQL driver -
no custom driver needed).
2. Host, Port, Username, Password: paste from the console's SQL access
panel. Database: leave "postgres".
3. SSL tab -> enable SSL. Test Connection -> Finish.
Gotcha: the database navigator shows exactly ONE database, named
"postgres", regardless of what your database is called in the
console. Your table namespaces appear as schemas under it (the
default namespace shows as "public"). Don't enable "Show all
databases" and go hunting for a database with your name on it;
there isn't one.1. Add New Server -> General: any name you like.
2. Connection tab: Host name/address, Port, Username, Password from
the console's SQL access panel. Maintenance database: leave
"postgres".
3. Parameters tab: SSL mode = Require. Save.
Gotcha: pgAdmin's Dashboard panels read PostgreSQL's statistics
tables (pg_stat_activity and friends), which this adapter does not
serve - expect empty panels or a polite error there. The object
browser and the Query Tool are the supported surfaces, and both work. pgAdmin 4, step by step.
The tab above is the short version; this is the full register-server pass. Open the console's SQL access tab first - every value below comes from it, and the password is shown once, when it's generated. Copy it before you leave the page.
- Register the server. Right-click Servers in the object explorer → Register → Server. On the General tab, give it any name you like.
- Connection tab. Host name/address: your database host from the SQL access tab - it looks like
<tenant-ulid>.ap-south-1.db.originchain.ai. Port:5432. Maintenance database:originchain, as the panel shows it - the field is cosmetic (see the note under connection details), and the browser tree shows a single database namedpostgreseither way. Username and Password: paste from the panel; tick Save password if you want pgAdmin to keep it. - SSL mode = Require. On the Parameters tab in current pgAdmin releases; older releases put it on a dedicated SSL tab next to Connection. There is no authentication setting to pick - pgAdmin negotiates SCRAM-SHA-256 automatically.
- Save. The object browser and the Query Tool are the supported surfaces. The Dashboard panels read PostgreSQL's statistics tables (
pg_stat_activityand friends), which this adapter does not serve - expect empty panels there, not data.
That's the IP Access List, not pgAdmin. The SQL port is reachable only from addresses on your instance's list, and an empty list means the port stays closed - every connection attempt times out. Add the address you connect from (console → your instance → Network access) and retry.
Sessions running under a database-user identity - which is what the SQL access tab issues - are read-only: every query is filtered by row-level security and column masking for that user, exactly as the HTTP API, and write statements are refused with SQLSTATE 0A000. Writes go through the HTTP SQL endpoint - the full story is under the limits section below.
ODBC (psqlODBC).
The standard PostgreSQL ODBC driver (psqlODBC) works - it speaks the same wire protocol as everything above. Install it, pick the Unicode variant, and map the DSN fields to the same values from the console's SQL access tab:
Driver PostgreSQL Unicode # psqlODBC - the stock PostgreSQL ODBC driver
Server <your-database-host> # looks like <tenant-ulid>.ap-south-1.db.originchain.ai
Port 5432
Database originchain # cosmetic - see the note under connection details
User Name <user> # console -> your instance -> SQL access
Password <password> # shown once, when it's generated - copy it then
SSL Mode require Or as one connection string, for anything that takes a DSN-less connection:
Driver={PostgreSQL Unicode};Server=<tenant-ulid>.ap-south-1.db.originchain.ai;Port=5432;Database=originchain;Uid=<user>;Pwd=<password>;SSLmode=require;
ODBC consumers connect under the database-user credential from the SQL access tab, and those sessions are read-only. Refreshing a workbook or report works, and every query is filtered by row-level security and column masking for that user - a report shows exactly what its user is allowed to see. Anything that tries to write back over the connection is refused with SQLSTATE 0A000; writes go through the HTTP SQL endpoint.
First connection timing out? Same cause as pgAdmin above - the IP Access List. Add your address under Network access first.
SQL compatibility.
The honest matrix. Works over wire means your SQL client runs it directly (and the HTTP SQL endpoint runs it too). API only means the capability exists, but through the HTTP API rather than your SQL client. Not yet means exactly that - we'd rather tell you here than have you find out in production. One caveat spans every row: write statements over the wire apply to a single-node instance without row or column controls. A session running under a database-user identity, and any replicated configuration, gets a read-only wire - see the limits below.
| Capability | Status | Notes |
|---|---|---|
| SELECT | works over wire | Simple and extended protocol, text and binary result formats. Typed columns come back with their real PostgreSQL types (NUMERIC, TIMESTAMPTZ, DATE, UUID, BYTEA, JSON, 1-D arrays, ...). |
| INSERT / UPDATE / DELETE | works over wire | Including RETURNING and INSERT ... ON CONFLICT. Constraint failures surface real SQLSTATEs (23505, 23502, 23503, ...), so driver error handling works unchanged. |
| transactions | works over wire | BEGIN / COMMIT / ROLLBACK, plus real savepoints (SAVEPOINT / ROLLBACK TO / RELEASE). Isolation is READ COMMITTED - see the limits below for what happens if you ask for more. |
| prepared statements | works over wire | Both kinds: the protocol-level flow every driver uses (Parse/Bind/Execute, text and binary parameters for the common scalar types) and SQL-level PREPARE / EXECUTE / DEALLOCATE. |
| stored procedures | works over wire | CREATE PROCEDURE / CREATE FUNCTION, CALL (including row-returning bodies), DROP PROCEDURE / FUNCTION. Routines are shared with the HTTP API - create on one surface, call from the other. |
| views | API only | CREATE VIEW and queries against views run over the HTTP SQL endpoint. Over the wire, CREATE VIEW is refused and a view's name doesn't resolve yet. |
| materialized views | API only | Plain CREATE MATERIALIZED VIEW name AS select works over the HTTP SQL endpoint and installs a real materialized view (OR REPLACE and WITH NO DATA are refused); the dedicated flow drives the same engine. Over the wire it is refused - see the limits below. |
| triggers | not yet | No trigger surface exists on either the wire or the HTTP API. CREATE TRIGGER is refused everywhere; there is no partial or emulated version to be surprised by. |
DDL over the wire, for completeness: CREATE TABLE and DROP TABLE are real (the drop cascades through rows and indexes, same as the API path). CREATE INDEX, CREATE SEQUENCE and ALTER TABLE are API-only for now. WITH (CTEs) is refused over the wire. COPY (both directions) is not supported yet on any client.
Limits, stated plainly.
SERIALIZABLE is refused, not faked.
Wire connections run at READ COMMITTED. If you ask for more - SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, BEGIN ISOLATION LEVEL REPEATABLE READ, or the equivalent session default - the server returns an error (SQLSTATE 0A000) naming the level it can't deliver. It never acknowledges the request and quietly gives you READ COMMITTED anyway. That's deliberate: a database that says yes and delivers less is lying to your correctness logic - write-skew protection you believe you have but don't is worse than an error at connection time. Levels at or below READ COMMITTED are accepted as-is, so drivers that set read-committed on connect work unchanged. Serializable transactions are available - through the HTTP transactions API, on single-node configurations.
Materialized-view DDL lives on the HTTP endpoint, not the wire.
Plain CREATE MATERIALIZED VIEW name AS select works over the HTTP SQL endpoint - it is populated at creation, and lands in the same refresh and inspection flow as views defined through the materialized views reference. Two forms are refused rather than half-honoured: OR REPLACE (drop, then create) and WITH NO DATA. Over the wire, CREATE MATERIALIZED VIEW is refused.
Row and column controls come with an identity - and a read-only wire.
Where column masks or row-security policies exist, the wire never serves data without knowing who is asking: enabling SQL access on an instance that carries them requires database-user credentials, and a listener that cannot resolve one refuses to serve those objects rather than read them in the clear. When a session does run under a database-user identity, every SELECT is filtered and masked for that user, per session, exactly as the HTTP API - and the session is read-only: every write verb (INSERT / UPDATE / DELETE, CREATE / DROP / ALTER / TRUNCATE, CALL, GRANT / REVOKE) is refused with SQLSTATE 0A000 and points you at the HTTP SQL endpoint for the write. Replicated configurations get the same read-only wire regardless of identity - an inline wire write would bypass the replication path.
Multi-node configurations refuse what they can't guarantee.
The same honesty rule applies across configurations: on a sharded or replicated setup, surfaces that can't uphold their guarantee are refused with a clear error rather than served with silently weaker semantics. Concretely: serializable API transactions are single-node only - a sharded configuration refuses to open one - and on replicated setups they are further restricted to point reads. If a request succeeds, its stated guarantee holds; if we can't hold it, you get an error you can code against.