@libredb/studio
v1.0.0
Published
The database editor that deploys next to your data, not onto your laptop.
Maintainers
Readme
Quick Start
Run a full Database Editor in one command, no clone, no build:
# Docker (recommended)
docker run -p 3000:3000 ghcr.io/libredb/libredb-studio:latest
# or with Node.js 24+ (no Docker)
npx @libredb/studioThen open http://localhost:3000. On first run, the admin password is printed to the log (zero-config).
If the browser reaches Studio at anything other than localhost or HTTPS (
http://192.168.x.x:3000on a LAN, for example), also setAUTH_COOKIE_SECURE=false. Without it the health check passes while login fails silently and sends you back to the login page.
Need Helm, Homebrew, Snap, winget, or deb/rpm? See all install options.
Live Test
Try LibreDB Studio instantly without installation!
| Test | URL | Credentials | |------|-----|-------------| | Public Test With OIDC | app.libredb.org | SSO | | Public Test With JWT | trial.libredb.org | [email protected] / Admin!2026 [email protected] / User!2026 |
The test instance comes with a pre-configured PostgreSQL database via Seed Connections. No setup required!
Overview
You create a Postgres on a managed platform. It is ready in forty seconds. Then you want to look inside it — so you open a port to the internet, dig an SSH tunnel, or install a desktop client on every machine that needs one.
LibreDB Studio goes the other way. It deploys next to the data: a container, a Helm chart, an operator, a one-click template on your PaaS, or npm i @libredb/studio inside your own product. Nothing has to face outward.
Forty-one engines share one interface: PostgreSQL, MySQL, Oracle, Db2 LUW, SQL Server, SQLite, libSQL, DuckDB, MongoDB, Redis, Couchbase, Firestore, ClickHouse, Druid, Elasticsearch, OpenSearch, Trino, BigQuery, Databend, Snowflake, Apache Spark, Apache Cassandra, Prometheus, Apache Kafka, etcd, Neo4j, Milvus, Qdrant, InfluxDB (InfluxQL), InfluxDB 3 (SQL), Oxia, S3-compatible object storage, Kubernetes, MQTT, RabbitMQ, OPC UA, MTConnect, Modbus, NETCONF, SNMP and Sparkplug B, with the same explorer everywhere, and ER diagrams, schema diff and monitoring wherever the engine has something to report. Three of the forty-one are read-only because their own SQL is: Druid, Elasticsearch and OpenSearch have no UPDATE and no CREATE TABLE in the grammar at all, so those controls are reported as unsupported instead of failing when used. Cassandra is the one that reports the least on purpose: it publishes no row count and no size that is true, so the object browser shows neither rather than showing a number that is wrong; the estimate it does publish counts partitions from flushed files, and it read 143 for a 500-row table. Trino is the other odd one: it is a query engine rather than a database, so it declares no keys and no indexes and reports the bytes as belonging to the systems behind its connectors.
Sparkplug B is the newest: one broker read over MQTT, the metrics an edge node's birth certificate declares and the values the data messages after it carry, read-only by construction, because the encoder has no function that writes a PUBLISH and the CONNECT carries no will: 5.4 registers an edge node's death certificate as its will, so a reader that set one would publish a death when its own socket dropped. A group and an edge node are containers, a metric is a row whose value, timestamp and definition come from the certificate that declared it, and a sequence gap is read from two consecutive data messages rather than guessed.
SNMP came before Sparkplug B: one agent read over UDP, the managed objects a numbered name points at, read-only by construction, because the outgoing valve refuses any PDU that is not a Get, GetNext or GetBulk, so a Set never reaches the socket. Four commands reach the agent, get, next, walk and table, and one file decides when a walk is over and nothing else does: the end of a subtree, a budget, an OID that did not move forward, or silence. An object group is a container, a walk over a subtree is the read, and a table is assembled from GetBulk answers. It speaks SNMPv2c today, and that is a fact about the connection form rather than a preference: the v3 security layer is written and measured byte for byte against its own captures, but the shared connection record carries no security level, privacy passphrase, context name or engine id pin, so there is nowhere for an operator to turn it on.
NETCONF came before SNMP: one network device read over NETCONF on SSH, read-only by construction, because requests.ts builds five request bodies and four of them are the reads, <get-config>, <get>, <get-data> and <get-schema>, while the fifth is the <close-session> that ends the connection: no function in the provider builds an <edit-config>, a <copy-config>, a <delete-config>, a <commit> or a <lock>. A datastore is a container at the first level and a YANG module one at the second, a module's top level container or list is an object, and a list entry's key leaves are the object's columns.
Modbus came before NETCONF: one device or gateway read over a raw socket, the registers and bits a map you supply names, and the device's own identification objects, read-only by construction, because the encoder names four read function codes and nothing else: there is no code in the provider that can build a write, and a valve re-checks every outbound byte before it reaches the socket. Modbus has NO DISCOVERY - no request lists what a device holds, and no register carries a name, a type or a unit - so the tree is built from that map rather than from the device, and a connection with no map says so instead of showing an empty one. A read is one JSON request: named points of the map, one range by address, or the identification objects.
MTConnect came before Modbus: one agent read over HTTP, the device model from its probe document and the observations from current and sample, with each asset's own XML in a Source tab, read-only by construction, because the request table holds nine routes and every one of them is a GET: there is no PUT, no POST and no stream anywhere in the provider. A device is a container, a data item and a condition are relations whose rows are value, timestamp and sequence, and an empty value is a third state rather than a missing one. The agent itself is a device like any other, which is worth knowing before an MCP client reads one: it carries its adapters' own addresses.
Apache Spark came before MTConnect: SQL typed in the editor runs on a self-hosted Spark 4.1 or later server over Spark Connect, gRPC with Arrow results, each request in a Spark session of its own; the tree shows catalogs and their namespaces with tables, views and functions, EXPLAIN FORMATTED plans a statement without running it, and a token travels only over TLS, on loopback or through an SSH tunnel.
OPC UA came before Apache Spark: one opc.tcp session reads a plant's address space into the Keys panel, one level at a time, with a node's value, status and attributes in a Source tab and raw history in the console, read-only by construction, because the client seam names eight read services and none of them writes: there is no Write, no Call and no subscription anywhere in the provider. A node's value is read from the node itself, so no bound is taken from the server's word: two of the four servers measured publish an operation limit they do not enforce, and one publishes zero for eight of them, so the chunk sizes are Studio's own. A method is listed and never called, and a history read says why it stopped rather than implying the history ended.
Snowflake came before OPC UA: SQL typed in the editor runs on a Snowflake account over its SQL API v2 with no driver, signed with a key pair or a programmatic access token, every statement as the one role the connection names; the tree shows databases and schemas with their tables, views, streams, tasks, stages and routines, EXPLAIN USING JSON compiles a statement without running it, and browsing the tree or testing the connection never starts a suspended warehouse.
RabbitMQ came before Snowflake: the management API browses virtual hosts, streams, queues and exchanges, and a JSON read request typed in the editor reads a stream's messages over AMQP 0-9-1 with no driver, read-only by construction, because Studio's own read client can encode no publish, take or declare, so it reads streams and never takes a message from a queue.
Firestore came before RabbitMQ: the Admin SDK query chain typed in the editor, such as db.collection("users").where("age", ">=", 30), reads a Google Cloud Firestore database over its REST API with no SDK, parsed by Studio and never run as JavaScript; the tree shows top-level collections, the Keys panel walks documents and subcollections at any depth, a document opens in a Source tab, and nothing Studio can send writes.
MQTT came before Firestore: one subscription reads a broker's topic tree into the Keys panel, with the server's own remaining lifetime beside each row and a topic's payload in a Source tab, read-only by construction, because the outbound path encodes only CONNECT, SUBSCRIBE, UNSUBSCRIBE, PINGREQ and DISCONNECT, there is no function that writes a PUBLISH, and the CONNECT carries no Will. MQTT has no command that lists topics, so no read claims to be complete: each one reports what it saw, why it stopped and what it can prove it lost, and $share/, $queue/ and $exclusive/ filters are refused before SUBSCRIBE because each takes messages away from the devices subscribed beside Studio.
Kubernetes came before MQTT: kubectl read commands typed in the editor read one cluster over the API server's REST API with no driver, the tree shows Cluster and the namespaces with their kinds and a YAML view of every object, a kubeconfig pastes into the connection dialog, and nothing Studio can send writes, runs a program or shows a Secret value.
S3-compatible object storage came before Kubernetes: AWS CLI read commands typed in the editor, such as aws s3api list-buckets, aws s3 ls, aws s3api head-object and aws s3api list-object-versions, and Studio's own preview read buckets and objects over the S3 REST API with no SDK, signed by Studio's own code with only the keys typed into the connection; the tree shows buckets, the Keys panel walks folders one level at a time, and an object opens with its metadata and a capped preview of text, JSON, CSV or Parquet, read-only by construction, because Studio sends only GET and HEAD requests; it is verified on MinIO, Silo, Garage and RustFS, and not on AWS S3 or any hosted service.
Databend came before S3-compatible object storage: SQL typed in the editor reads and writes a self-hosted Databend server or a Databend Cloud warehouse over Databend's own HTTP query API with no driver, the browser shows catalogs and databases with their tables, views, materialized views and dynamic tables, and each statement runs in a session of its own, so a transaction ends with the statement that opened it.
Oxia came before Databend: oxia client read commands typed in the editor read an Oxia 0.16.10 or 0.17.1 server over its gRPC client API, the tree shows shards and the Keys panel every key, read-only by construction, because the client can call only the four read RPCs and the health check, and Studio dials a shard leader only when it is the address the connection names or a listed data server.
InfluxDB came before Oxia, as two connection types, one per query language: InfluxDB (InfluxQL) sends InfluxQL over InfluxDB's v1 HTTP API to InfluxDB 1.x, 2.x and 3, and InfluxDB 3 (SQL) sends SQL to InfluxDB 3 Core and Enterprise over its SQL API; the browser shows databases with their measurements, or tables on InfluxDB 3, and both are read-only whatever the connection says, because every statement that is not a read is refused before any request and Studio calls no write endpoint.
Milvus came before InfluxDB: Milvus's own REST v2 requests typed in the editor read a Milvus 3.0.2 server over its gRPC API, the browser shows databases and collections with their fields, partitions, indexes and load state, and vectors reach the grid as vector cells, read-only apart from an admin's Load and Release, because the console runs fifteen read routes and refuses every request that would make the server call another service.
Qdrant came before Milvus: Qdrant's own REST requests typed in the editor read a Qdrant 1.19.1 server, the browser shows collections with their vectors, payload indexes and a sampled view of payload keys, and vectors reach the grid as vector cells, read-only by construction, because the console runs seventeen read routes and refuses every inference input except the local BM25 model.
Neo4j came before Qdrant: Cypher typed in the editor reads a Neo4j 5.26 database over Bolt, the browser shows node labels, relationship types, indexes and constraints, and nodes, relationships and paths reach the grid as JSON cells, read-only by construction, because every statement passes a read policy, the server's own classification (which an allowlisted SHOW form skips) and a READ session before it runs.
etcd is the one before it: an etcdctl subset over etcd's gRPC API reads and writes keys, the browser shows key-prefix groups and a key browser, a key's value is edited in one transaction guarded by its revision, and an admin can compact, defragment and disarm alarms, while every write under a Kubernetes prefix is refused and every Kubernetes secret withheld.
Apache Kafka came before etcd: a JSON read request reads a topic's messages over the Kafka protocol, by partition, offset or timestamp, and the browser shows topics, consumer groups with their lag, and brokers, read-only by construction, because Studio never produces, commits an offset, joins a consumer group or creates a topic.
None of OPC UA, Kubernetes, S3-compatible object storage, Oxia, InfluxDB (InfluxQL), Milvus, Qdrant, Neo4j, etcd, Apache Kafka, MQTT, RabbitMQ and Prometheus is SQL at all, as MongoDB and Redis are not: InfluxQL looks like SQL and is its own language, one SELECT, SHOW or EXPLAIN per run here, while InfluxDB 3 (SQL) is SQL; Prometheus speaks PromQL over the Prometheus HTTP API, browses metrics, rules and scrape targets, and is read-only because Studio calls none of the server's write or admin endpoints.
And nothing is held back. Single sign-on, ER diagrams, the AI features and the NoSQL engines all ship in the MIT build. MIT is not generosity here, it is a requirement of the architecture: you cannot place a per-seat licensed, feature-gated tool into every environment you own.
Why LibreDB Studio?
- Deploys next to the data: container, Helm chart, Rancher, OpenShift operator, one-click PaaS template, or embedded via npm.
- Forty-one engines, one interface: PostgreSQL, MySQL, Oracle, Db2 LUW, SQL Server, SQLite, libSQL, DuckDB, MongoDB, Redis, Couchbase, Firestore, ClickHouse, Druid, Elasticsearch, OpenSearch, Trino, BigQuery, Databend, Snowflake, Apache Spark, Cassandra, Prometheus, Apache Kafka, etcd, Neo4j, Milvus, Qdrant, InfluxDB (InfluxQL), InfluxDB 3 (SQL), Oxia, S3-compatible object storage, Kubernetes, MQTT, RabbitMQ, OPC UA, MTConnect, Modbus, NETCONF, SNMP, Sparkplug B.
- Runs where you are: browser, phone, Windows, MacOS, Linux desktop.
- A read-only agent, with your own model: state a question, and the run drafts SQL, reads the results, and writes a report whose claims cite them. Gemini, OpenAI, or a local Ollama with open-source models.
- Nothing behind a wall: RBAC, OIDC single sign-on, query audit trail, and ER diagrams all ship under MIT.
Key Features
Professional SQL IDE
- Monaco Engine: Powered by the same core as VS Code.
- Smart Autocomplete: Schema-aware suggestions for tables, columns, and SQL keywords.
- Command Palette: Quick access to tables, connections, saved queries, and actions with
Cmd/Ctrl+K. - Multi-Tab Workspace: Handle parallel tasks with independent execution states.
- Saved Query Backups: Export the complete saved-query library as JSON. Import validates the file, preserves query metadata and merges new entries, reporting duplicate IDs while keeping existing queries intact.
- Duplicate Connections: Open an independent
(copy)of an editable saved connection in the connection editor, adjust its settings and save. Cancelling leaves the saved connections unchanged; administrator-managed connections cannot be duplicated. - Visual EXPLAIN: Graphical execution plans to identify performance bottlenecks.
- Interactive ER Diagrams: Visual schema graph with real foreign key edges, cardinality labels, MiniMap navigation, table search/filter, compact mode, and PNG/SVG export. Automatic hierarchical layout powered by ELK.js.
- Schema Diff & Migration: Compare schema snapshots or cross-connection schemas side-by-side. Color-coded diff view (added/removed/modified) with automatic migration SQL generation for PostgreSQL, MySQL, SQLite, Oracle, and SQL Server, plus ClickHouse column modifications.
- Snapshot Timeline: Visual horizontal timeline of schema snapshots. Click any two points to instantly compare and track schema evolution over time.
The Database Agent
Studio's main AI surface is an agent rail beside the editor; the model-backed helpers listed below it are the others. You state an objective: "which department has the most employees?", "why is this query slow?"; and press Start. The run drafts SQL against the connected database, reads what comes back, and finishes by composing a report whose every claim cites the result it came from.
- Read-only, enforced by the database rather than by a parser. Every statement the agent runs
goes through the agent's own audited pipeline — a policy decision, an audit event and budget
accounting before the driver is touched (
executeAuditedOperation,src/lib/db/operations/execution.ts:129) — under a read-only execution profile: a read-only transaction on PostgreSQL,PRAGMA query_onlyre-asserted per statement on SQLite, aREAD_ONLYengine handle on DuckDB paired with an SQL-level guard, because that flag alone still letsCOPY … TO,EXPORT DATABASEand the local-file table functions through, and, on SQL Server, which has no read-only transaction of any kind, a session principal verified at open to be unable to write, an optimizer admission that compiles each statement without running it, a server-side row bound, and a transaction that is always rolled back. Writes and DDL are refused before the database is reached, andEXPLAIN ANALYZEis default-denied because it would run the statement. This pipeline is the agent's alone: statements you run yourself in the editor call the provider directly (src/app/api/db/query/route.ts:44) and are neither policy-checked nor audited this way. - Agent mode reads PostgreSQL, SQLite, DuckDB, SQL Server, MySQL, Kubernetes and MongoDB. The read-only profile
exists only where a provider implements it:
queryReadOnlyonpostgres.ts,sqlite.ts,duckdb/index.ts,mssql.ts,mysql.ts,kubernetes/index.tsandmongodb/index.ts, and nowhere else. On Kubernetes the boundary is Studio's request allowlist plus the agent identity's RBAC. On MongoDB it is the connection's user: before a run that sends commands reaches its first model turn, the server must show that the user holds only read privileges on the bound database and must refuse a write from it. On any other engine an Agent-mode run whose workflow sends statements is refused when it is started, before a run is opened, and any that reaches the provider factory endsengine-unsupported. Plan mode opens on every connection — the model there is toolless, runs no statement of yours, writes nothing, and drafts a statement for you to run yourself. Its GROUNDING reaches every engine: on PostgreSQL and SQLite the server composes catalog statements itself, and on every other connection it asks that connection's own provider to describe its schema — the reading the sidebar already performs — which needs no read-only statement path. So the two limits are separate: agent mode is the engines named above, grounding is all of them, and a run whose reading fails says so plainly rather than inventing tables. - Three workflows: Investigate (answer a question), Optimize (compare estimated plans, propose an index or a rewrite), Assess (profile tables — counts only, never values).
- Nothing runs itself. The agent never starts a run for you, never writes to the editor, and never executes what it recommends. Applying a statement is your click.
- Evidence or nothing. A claim with no citation cannot be composed, and the run states its own verdict — "Run answered" or "Run did not answer" — beside how it ended.
- Bounded, and the meter is on screen: 18 to 45 statements and a 360 s to 900 s run deadline depending on workflow, 200 rows per read. See docs/AGENT.md for the exact figures per workflow.
- Your own model. Gemini (the default), OpenAI, Ollama, or any OpenAI-compatible endpoint.
Agent mode needs a model that can call tools — on Ollama, a live probe, not the vendor's page,
is what establishes that, and the guide says how to run one. Plan mode needs no tools and is
never probed (
src/lib/agent/capability-gate.ts:74), so a model refused for Agent mode can still be used in Plan mode, which is what the rail offers you. - No model configured, no AI. With no
LLM_*settings at all, the rail does not render, and nothing leaves your network. Note that a key is not the switch: Ollama and a custom endpoint count as a configured model without one, and then the AI is on. What the agent sends isdocs/AGENT_DATA_FLOW.md.
Standalone application only: the embedded @libredb/studio package carries no agent surface.
Guide: docs/AGENT_GUIDE.md · What leaves the machine:
docs/AGENT_DATA_FLOW.md · Behaviour and limits:
docs/AGENT.md · Which local model to run:
docs/llms/
Model-backed helpers
- Universal LLM Support: Defaults to Gemini and serves OpenAI, Ollama, and any OpenAI-compatible endpoint (LM Studio, LiteLLM, vLLM).
- Query Safety Analysis: AI-powered pre-execution risk assessment for destructive queries (DELETE, DROP, TRUNCATE). With no provider configured, the confirmation remains available with a plain query warning. Setting
LLM_PROVIDERwithout its credentials is an unfinished setup, so that error stays visible, as do other configuration and service errors. - AI Query Explainer: EXPLAIN plans translated into plain language with optimization suggestions.
- Schema Awareness: the connected database's schema is sent as context, so an explanation names your own tables and columns.
- Data Profiler summary: the profiler's per-column statistics written up in prose. That context carries each column's
minandmax, which are real values from your data; see Agent Data Flow.
Pro Data Management
- Universal Data Grid: Virtualized rendering (TanStack) for millions of rows.
- Inline Editing: Double-click to update values directly in the grid, on engines whose SQL has a single-table row update (the control is hidden elsewhere).
- Column Filtering: Per-column text filters on query results for instant data exploration.
- Interactive Pivot Table: Client-side pivoting with 5 aggregation functions (COUNT, SUM, AVG, MIN, MAX) and SQL generation.
- Expert Exporter: Instant CSV and JSON exports for reporting. CSV import and result export offer comma (default), semicolon and tab separators. Every format the Export menu writes to a file it also copies straight to the clipboard.
Advanced Data Visualization
- 8 Chart Types: Bar, Line, Pie, Area, Scatter, Histogram, Stacked Bar, and Stacked Area charts powered by Recharts. A NULL category is drawn as its own category named
NULL, the word the results grid shows, and every value stays on its own row's category; a cell holding the textNULLreads the same on the axis, and an empty-string category is its own, blank-labelled category. - Data Aggregation: Group-by with SUM, AVG, COUNT, MIN, MAX aggregation functions. Date grouping by hour, day, week, month, or year.
- Chart Persistence: Save chart configurations and reload them instantly. Manage a library of saved charts.
- Chart Dashboard: Grid view of all saved charts for at-a-glance data overview directly in the bottom panel.
Display Masking (Preview)
- Client-Side Display Layer: Masks sensitive values in the browser UI — useful for screen sharing, demos, and reducing accidental on-screen exposure. Not server-enforced; query API responses still contain full values for authenticated users.
- Column-Name Pattern Matching: 10 built-in patterns (email, phone, credit card, SSN, password, IP, date, financial, and more) match result column headers by regex. Works when the output name matches (e.g.,
SELECT salary). Aliases (salary AS x) and aggregates (SUM(salary)) are not masked today. - Configurable Rules: Admin panel to add, edit, enable/disable masking patterns. Email, phone, credit card and SSN presets prefill the Add Pattern form so column patterns can be adapted before saving. Custom patterns support regex. Settings stored per-browser in localStorage.
- RBAC UI Controls: User role cannot toggle or reveal masked cells in the UI. Admin role can toggle masking and temporarily reveal individual cells (10s auto-hide).
- Export & Clipboard: CSV, JSON, and SQL INSERT exports, whether saved as a file or copied to the clipboard, use masked display values when masking is active in the UI. This does not prevent access to raw data via the API, browser DevTools, or admin reveal.
- UI Coverage: Grid, mobile card/table views, row detail sheet, and clipboard copy respect the active display mask.
Analyst & Developer Tools
- AI Data Profiler: One-click table profiling with column statistics (null %, cardinality, min/max, sample values) and AI-powered narrative summaries.
- ORM Code Generator: Generate TypeScript interfaces, Zod schemas, Prisma models, Go structs, Python dataclasses, and Java POJOs from live table schemas.
- Test Data Generator: Schema-aware fake data generation with 30+ semantic column inferences (email, phone, name, address, etc.). Produces INSERT statements or MongoDB insertMany JSON.
- Database Documentation: Auto-generated searchable data dictionary from live schema with AI-powered documentation and Markdown export.
Authentication & SSO
- Dual Auth Modes: Local email/password login or OpenID Connect (OIDC) Single Sign-On; switchable via environment variable.
- Vendor-Agnostic OIDC: Works with any OIDC-compliant provider — Auth0, Keycloak, Okta, Azure AD, Zitadel, Google, and more.
- One-Command SSO Demo:
docker compose -f docker-compose.oidc-demo.yml upstarts Studio with a preconfigured Keycloak so you can try SSO and role mapping locally (walkthrough). - PKCE Security: Authorization Code Flow with Proof Key for Code Exchange (S256) for secure authentication.
- Auto Role Mapping: Configurable claim-based role mapping with dot-notation for nested claims (e.g.,
realm_access.roles). - Provider Logout: Logout clears both the local JWT session and identity provider session.
- Passkeys: Local accounts in the server store (
STORAGE_PROVIDER=sqliteorpostgres) can sign in with a passkey instead of a password and code oncePASSKEY_ORIGINnames the address people open Studio at (guide). - Launch sign-in: A platform that hosts Studio can sign its users in with a short-lived signed link and open a seeded connection, once
LAUNCH_TOKEN_SECRET,LAUNCH_TOKEN_AUDIENCEandLAUNCH_TOKEN_ISSUERare set (guide).
DBA Maintenance Toolkit (Admin Only)
- Live Monitoring Dashboard: 7-tab monitoring with Overview, Performance, Queries, Sessions, Tables, Storage, and Connection Pool views.
- Time-Series Trend Charts: Real-time metric trends (connections, cache hit ratio, buffer pool, deadlocks) with auto-refreshing ring buffer history.
- Configurable Auto-Refresh: Polling intervals from 5s to 60s with play/pause control.
- Threshold Alerting: Color-coded health indicators (healthy/warning/critical) for cache hit ratio, connection usage, deadlocks, and buffer pool utilization.
- Connection Pool Stats: Live total/active/idle/waiting pool metrics with utilization progress bars.
- One-Click Maintenance: Trigger
VACUUM,ANALYZE,REINDEX,UPDATE STATISTICS,DBCC CHECKDB, andALTER INDEX REBUILDper database engine. - Audit Trail: Full history of every query executed across the organization. The admin Audit tab exports loaded operations and query history as CSV or JSON, respecting the current filters.
Supported Databases
| Database | Driver | Features |
| :--- | :--- | :--- |
| PostgreSQL | pg | Full SQL IDE, EXPLAIN plans, transactions, query cancellation (pg_cancel_backend) |
| MySQL | mysql2 | Full SQL IDE, EXPLAIN plans, transactions, query cancellation (KILL QUERY) |
| Oracle | oracledb (Thin mode) | Full SQL IDE, FETCH FIRST N ROWS pagination, V$ monitoring views, ANALYZE TABLE, ALTER INDEX REBUILD, transactions |
| Db2 LUW | db2-node (a Rust DRDA client in a native N-API addon, no IBM client) | SQL IDE against Db2 for Linux, UNIX and Windows: schema browser with tables, views, materialized query tables, aliases, sequences, modules, routines and triggers, stored definitions, FETCH FIRST / OFFSET pagination, RUNSTATS and REORG per table, inline editing and import into existing tables. TLS is required unless you opt out, because without it the password crosses the network in cleartext. A value bound to a large CLOB, DBCLOB or BLOB column is not written and no error says so, so the table preview leaves those columns out and offers no edit of them; Create Table, EXPLAIN, transactions and cancel are off. The known issues are listed in docs/providers/db2.md |
| SQL Server | mssql (tedious) | Full SQL IDE, TOP N / OFFSET FETCH pagination, sys.dm_* DMVs, UPDATE STATISTICS, DBCC CHECKDB, transactions, Azure SQL auto-detect |
| SQLite | bun:sqlite / node:sqlite (runtime-selected) | Full SQL IDE, file-based or in-memory databases (server-local file) |
| libSQL | none — HTTP (the Hrana protocol, POST /v2/pipeline, port 8080) | Full SQL IDE against a libSQL server or Turso Cloud — the same SQLite dialect as the row above, reached across a network instead of on disk. EXPLAIN QUERY PLAN, sqlite_master and pragma_* introspection, and real per-table bytes from dbstat, which the file-based driver above cannot read. The credential is an auth token rather than a password. Two maintenance operations only, REINDEX and PRAGMA integrity_check: the server refuses VACUUM, ANALYZE, PRAGMA optimize and PRAGMA wal_checkpoint outright, so no control is offered for them |
| DuckDB | @duckdb/node-api (a native N-API addon, ~68 MB of platform bindings) | Full SQL IDE against a local DuckDB file or :memory:, on the server the app runs on. EXPLAIN (FORMAT JSON) physical plan trees, duckdb_* catalog introspection, real per-table bytes from pragma_storage_info block allocation, and query cancellation through the driver's own interrupt(). Three maintenance operations, VACUUM, ANALYZE and CHECKPOINT: REINDEX is a parser error here and neither PRAGMA integrity_check nor PRAGMA optimize exists, so no control is offered for them. No slow-query log and no session list — DuckDB publishes neither, so those panels say so rather than showing a zero. The file admits exactly ONE operating-system process, refused in read-only mode too, so a second Studio instance cannot open a database this one holds |
| MongoDB | mongodb | JSON query editor, collection operations (find, aggregate, insert, update, delete) |
| Couchbase | none — HTTP (Query + management REST) | Full SQL++ IDE, EXPLAIN plans, bucket/scope/collection explorer, INFER column inference, read-your-writes consistency, UPDATE STATISTICS / BUILD INDEX / request kill |
| Firestore | none, REST (the Firestore REST API v1) | Read-only: top-level collections in the tree, documents and subcollections at any depth in the Keys panel, a document's data in the Source tab, and the Admin SDK query chain parsed by Studio and never run as JavaScript, with count(), sum(), average(), findNearest and Query Explain |
| ClickHouse | none — HTTP (SQL interface, port 8123) | Full SQL IDE, JSON EXPLAIN plan trees, system-table schema introspection, OPTIMIZE TABLE / table statistics / query kill maintenance |
| Apache Druid | none — HTTP (POST /druid/v2/sql, Router port 8888 or Broker 8082) | Read-only SQL IDE, native-query EXPLAIN plan trees, INFORMATION_SCHEMA datasource introspection, sys.* monitoring (segments, servers, ingestion tasks). Druid SQL has no UPDATE, no DELETE and no CREATE TABLE, and nothing it can do counts as a maintenance operation — a datasource changes through ingestion, not from the editor |
| Elasticsearch | none — HTTP (POST /_sql?format=json, port 9200) | Read-only SQL IDE, mapping-driven index/field explorer, cluster health plus per-index document counts and store sizes. No EXPLAIN, no maintenance operation, no slow-query or session panel: those live in log files and stats APIs the SQL surface does not reach. Elasticsearch SQL also has no OFFSET, so a second page of results cannot be requested — narrow the statement or raise the limit instead |
| OpenSearch | none — HTTP (POST /_plugins/_sql, port 9200) | The same read-only SQL IDE and explorer, from the same provider module. LIMIT n OFFSET m does work here, so paging does |
| Trino | none — HTTP (the client protocol, POST /v1/statement, port 8080) | Full SQL IDE across every configured catalog, EXPLAIN (FORMAT JSON) plan trees, information_schema schema tree for the catalog the connection pins, system.runtime + jmx monitoring, real SHOW STATS row counts, query cancellation and kill_query maintenance. Trino is a query engine and stores nothing, so it declares no primary keys, no foreign keys and no indexes anywhere — the ER diagram draws boxes and no edges, inline row editing is switched off, and the size panels name the catalogs rather than inventing a footprint. A failed statement arrives as HTTP 200, and a password is refused over plain HTTP even on a cluster with authentication disabled |
| Databend | none, HTTP (Databend's own query API, POST /v1/query, port 8000) | SQL IDE against a self-hosted Databend server or a Databend Cloud warehouse: catalogs and databases in the tree with tables, views, materialized views and dynamic tables, plain EXPLAIN text plans, system.* monitoring of the default catalog, and query cancellation with KILL QUERY from the Sessions panel. Each statement runs in a session of its own, so a transaction or a temporary table ends with the statement that opened it. Databend declares no keys, so inline row editing is off, and so is Create Table. A password over plain HTTP to a host that is neither loopback nor tunnelled is refused unless the connection consents. A Cloud connection names its warehouse, which resumes, and bills, on the first statement, opening the connection included, since it reads the object tree. TLS with a custom CA and client certificates; SSH tunnel |
| BigQuery | none, HTTP (the BigQuery REST API, jobs.query) | SQL (GoogleSQL) IDE: projects, datasets, tables, views and materialized views in the tree, statements through jobs.query. EXPLAIN is a dry run that reports the bytes processed. Service-account key or access-token credentials; no driver |
| Snowflake | none, HTTP (the Snowflake SQL API v2) | SQL IDE: databases, schemas, tables, views, streams, tasks, stages and more in the tree, one statement per request. EXPLAIN USING JSON compiles without running. Key-pair or programmatic-access-token sign-in, every statement as one role; no driver |
| Apache Spark | @grpc/grpc-js and apache-arrow, gRPC (Spark Connect, Spark 4.1 and later) | SQL IDE: catalogs and namespaces with their tables, views and functions in the tree, one Spark session per request, EXPLAIN FORMATTED plans without running. Token over TLS, on loopback or through an SSH tunnel; agent plan mode |
| Apache Cassandra | cassandra-driver (pure JS, no native module) | CQL IDE over the native protocol (port 9042), keyspace browser marking partition and clustering keys, system_views overview, uptime and running statements. No EXPLAIN (the keyword is not in CQL), no cancellation (the protocol has none), no maintenance (every operation is a nodetool action), and no row counts or sizes: the only figures Cassandra publishes are partition estimates from flushed files and whole mebibytes, so neither is shown rather than shown wrong |
| Prometheus | none, HTTP (the Prometheus HTTP API, port 9090) | PromQL editor whose text reaches the server unchanged, results in the grid and the chart tab (a stepped subquery such as rate(x[5m])[1h:1m] charts as lines over its timestamps: the tab opens on the first series, more are added from the Y-Axis menu, one line each, and at most eight are drawn at once, past which it says "Showing first 8 of N series"; but the chart draws a missing sample, and a NaN or Inf among numbers, at 0, so a raw range over targets scraped at their own offsets charts false zeros), a metric browser with label names as columns and metadata as the source, rule groups with recording and alerting rules (a firing alert is marked in the tree), scrape pools and targets (a down target is marked), and health, version, uptime and TSDB statistics. Read-only by design: no admin API, no remote write, no EXPLAIN (the parse endpoint is experimental) and no maintenance. A credential over plain HTTP is sent rather than refused, so enable TLS across a network you do not control |
| Apache Kafka | @platformatic/kafka (pure TypeScript, port 9092) | A JSON read request that reads a topic by partition, offset or timestamp, from its earliest offset or its latest messages, with keys, values and headers decoded as JSON, text or base64 and a Confluent-framed value labelled with its schema id; a topic browser with partitions and non-default configs (an offline or under-replicated topic is marked), consumer groups of both protocols with lag per partition, brokers with their configs, and health, topic counts and size on disk. Read-only by construction: no produce, no commit, no group membership and no topic creation. TLS with a custom CA and client certificates, and SASL PLAIN or SCRAM over TLS only; no SSH tunnel, because the brokers are reached at the addresses they advertise |
| etcd | @grpc/grpc-js (pure JavaScript, gRPC, port 2379) | An etcdctl subset in the editor (get, put, del, txn, leases, a bounded watch, members, alarms, users and roles); key-prefix groups in the tree and every key in the Keys panel; a key's value edited in one transaction guarded by its revision; compaction, defragmentation and alarm disarm for admins, each confirmed by typing the connection's name. Every write under a Kubernetes prefix or to compact_rev_key is refused, and Kubernetes secrets and protobuf or encrypted values are never shown. TLS with a custom CA, client certificates (their Common Name as the etcd user) and password sign-in over TLS only; SSH tunnel; a seed-declared read-only mode |
| Neo4j | neo4j-driver-lite (pure JavaScript, Bolt, port 7687) | Read-only Cypher in the editor, one statement per run, against Neo4j 5.26 LTS; node labels and relationship types with their properties as columns, indexes and constraints in the tree; nodes, relationships and paths as tagged JSON cells in the grid, with 64-bit integers and temporal values kept exact; the monitoring panels Community serves. Every statement passes a read policy over its tokens, then the server's own classification through EXPLAIN, which runs only a read or an allowlisted procedure call and which an allowlisted SHOW form skips, and runs in a READ session, so a write has to defeat all three. No EXPLAIN or PROFILE view, no maintenance, no agent execution and no MCP run_read_query. TLS with a custom CA and SSH tunnel; no connection string |
| Milvus | @grpc/grpc-js (pure JavaScript, gRPC, port 19530) | Milvus's own REST v2 requests in the editor (POST /v2/vectordb/<route> with one JSON body) for reads, exact counts and vector searches over every vector type, BM25 and hybrid search included; databases and collections in the tree with fields, partitions, indexes and load state; vector cells with their dimension and full-value copy; Load and Release for admins, previewed and confirmed. Studio writes no data, refuses requests that would make the server call another service, and warns about the default root password. TLS with a custom CA and client certificates; a password only over TLS, on loopback or through the SSH tunnel; a seed-declared read-only mode |
| Qdrant | none, HTTP (Qdrant's REST API, port 6333) | Qdrant's own REST requests in the editor (METHOD /path with one JSON body), seventeen read routes: point reads, scrolls, exact counts, facets, and queries, batches and grouped queries over dense, sparse and multivector data, the local BM25 model included; collections in the tree with their vectors, payload indexes and a sampled view of payload keys; vector cells with their dimension and full-value copy. Studio writes nothing, refuses every inference input except local BM25, and warns about a JWT with no expiry or manage access. TLS with a custom CA and client certificates; a key only over TLS, on loopback or through the SSH tunnel; a seed-declared read-only mode |
| InfluxDB (InfluxQL) | none, HTTP (InfluxDB's v1 API, port 8086) | Read-only InfluxQL in the editor against InfluxDB 1.x, 2.x and 3 over the v1 /query API, one SELECT, SHOW or EXPLAIN per run; databases and measurements in the tree, a measurement's tags and fields as its columns, and integers beyond 2^53 and nanosecond timestamps kept exact in the grid. Read-only whatever the connection says: on 1.x and 2.x Studio's own read policy is the only boundary before DROP DATABASE, so every other statement is refused before any request, and no write endpoint is reached. A user and password, or a token in the password field; a credential over plain HTTP to a host that is neither loopback nor tunnelled is refused unless the connection consents; _internal is never read on an InfluxDB 3 server |
| InfluxDB 3 (SQL) | none, HTTP (InfluxDB 3's SQL API, port 8181) | Read-only SQL in the editor against InfluxDB 3 Core and Enterprise; the tables of the connection's database in the tree with their columns. Read-only whatever the connection says: the route table reaches no write, token, cache or plugin endpoint, and of the configure endpoints only the database listing, a GET, every statement that does not lead with a read keyword is refused before any request, and the server's planner refuses every write besides. A token, and no user name; a token over plain HTTP to a host that is neither loopback nor tunnelled is refused unless the connection consents; pointed at a 1.x or 2.x server it says to pick InfluxDB (InfluxQL) instead |
| Oxia | @grpc/grpc-js (pure JavaScript, gRPC, port 6648) | Read-only oxia client commands (get, list, range-scan), shards in the tree, every key in the Keys panel |
| S3-compatible object storage | none, HTTP (the S3 REST API, path style, signed by Studio's own SigV4 code; hyparquet for Parquet previews) | Read-only AWS CLI read commands such as aws s3api list-buckets, aws s3 ls, aws s3api head-object and aws s3api list-object-versions, plus Studio's own preview; buckets in the tree and folders in the Keys panel, one level at a time; an object's metadata and a capped preview of text, JSON, NDJSON, CSV, TSV and Parquet, hex for anything else. Only the keys typed into the connection sign, never the server's own AWS identity, and the link-local networks, where AWS, Azure and Google Cloud serve instance metadata, are always refused, as is AWS's IPv6 metadata address. Verified on MinIO, Silo, Garage and RustFS; AWS S3 and hosted services are not verified |
| Kubernetes | none, HTTP (the API server's REST API, port 6443) | Read-only: a kubectl subset in the editor (get, describe, logs, top, events, explain, auth can-i), namespaces and their kinds in the tree with a YAML view of every object, and a kubeconfig import in the connection dialog. Secret values are never shown. TLS with the cluster's CA and client certificates; SSH tunnel |
| MQTT | mqtt-packet (its parser only; the five packets Studio sends, the connection manager and the one-way valve are Studio's own) | Read-only by construction: the outbound path encodes only CONNECT, SUBSCRIBE, UNSUBSCRIBE, PINGREQ and DISCONNECT, there is no function that writes a PUBLISH, and the CONNECT carries no Will. The Keys panel builds a topic tree from one subscription, with the server's own remaining lifetime beside each row, and a topic opens with its payload and metadata. MQTT has no command that lists topics, so no read claims to be complete: each one reports what it saw, why it stopped and what it can prove it lost. $share/, $queue/ and $exclusive/ filters are refused before SUBSCRIBE, because each takes messages away from the devices subscribed beside Studio. Verified on Mosquitto, EMQX, HiveMQ CE, NanoMQ and RabbitMQ 4 |
| RabbitMQ | none: the management HTTP API (port 15672) and Studio's own AMQP 0-9-1 read client (port 5672) | Read-only by construction: the read client encodes no publish, take or declare. Virtual hosts, streams, queues and exchanges in the tree; a JSON read request reads a stream's messages, never a queue's |
| OPC UA | node-opcua-client (pure JavaScript, opc.tcp, port 4840) | Read-only by construction: the client seam names eight read services - GetEndpoints, CreateSession, ActivateSession, Browse, BrowseNext, Read, HistoryRead and CloseSession - and there is no Write, Call, HistoryUpdate or subscription in the provider at all. The Keys panel walks the address space one level at a time, one Browse a level, by an escaped browse path, because a browse name may contain the separator; a node opens with its value, status, both timestamps and its decoded AccessLevel, and the console reads current values or raw history as one JSON request. Every bound is Studio's own rather than the server's published limit: of the four servers measured, two serve requests well past the limit they publish and one publishes zero. A method node is listed and never called. Measured against Microsoft OPC PLC 2.15.10, open62541 1.5.9, Python asyncua 2.1.0 and the Eclipse Milo demo |
| MTConnect | none: Studio's own client over the shared node:http(s) transport (port 5000) | Read-only by construction: the request table holds nine routes and every one of them is a GET, so there is no PUT, POST or stream to send. A device is a container, a data item and a condition are relations whose rows are value, timestamp and sequence, and each asset's own XML opens in a Source tab |
| Modbus | none: Studio's own client over a raw socket through the shared egress rule (port 502, or 802 for MODBUS/TCP Security) | Read-only by construction: the encoder names four read function codes and device identification, and no function builds a write; a valve re-checks every outbound byte. Modbus has no discovery, so the tree is built from a register map kept with the connection, and a read is one JSON request against the points that map names |
| NETCONF | ssh2 (the SSH transport only; Studio opens the socket and hands it over, and the NETCONF framing, requests and session are Studio's own, port 830) | Read-only by construction: requests.ts builds five request bodies and four of them are the reads, <get-config>, <get>, <get-data> and <get-schema>, while the fifth closes the session, and no function builds an <edit-config>, a <copy-config>, a <commit> or a <lock>. A datastore is a container and a YANG module one below it, a module's top level container or list is an object, and a list entry's key leaves are the object's columns |
| SNMP | none: Studio's own client over UDP (port 161), through the shared egress rule | Read-only by construction: the outgoing valve refuses any PDU that is not a Get, GetNext or GetBulk, so a Set never reaches the socket. An object group is a container, a walk over a subtree is the read, and a table is assembled from GetBulk answers |
| Sparkplug B | none: Studio's own bounded MQTT session over the shared node:net and node:tls transports (port 1883, or 8883 through the SSL / TLS panel) | Read-only by construction: the encoder has no function that writes a PUBLISH, and the CONNECT carries no will, because 5.4 registers an edge node's death certificate as its will and a reader that set one would publish a death when its own socket dropped. A group and an edge node are containers, and a metric is a row whose value, timestamp and definition come from the birth certificate that declared it |
| Redis | ioredis | Command editor, key browser, INFO-based monitoring |
Twenty-seven more engines have no driver of their own. The forty-one above are the drivers this build ships. Twenty-seven further engines speak one of those wire protocols and connect through an existing driver unchanged, so forty-one drivers reach sixty-eight named engines in all. They are MariaDB, Percona Server for MySQL, TiDB, Vitess, StarRocks, Apache Doris, OceanBase, SingleStore, Citus, Percona Distribution for PostgreSQL, ParadeDB, OrioleDB, TimescaleDB, YugabyteDB, AlloyDB Omni, Apache Cloudberry (incubating), CockroachDB, Materialize and RisingWave (as PostgreSQL or MySQL), Valkey, DragonflyDB, KeyDB and Garnet (as Redis), FerretDB (as MongoDB), ScyllaDB (as Cassandra), VictoriaMetrics (as Prometheus), and Redpanda (as Apache Kafka). Each was measured against a live instance, and how much of the product works differs per engine. MariaDB, both Percona distributions, TiDB, Vitess, AlloyDB Omni, Citus, TimescaleDB, YugabyteDB, ParadeDB, OrioleDB, Valkey, DragonflyDB, KeyDB and FerretDB behave as their driver's own engine, though three of them report statistics you should not trust: a Citus distributed table and a TimescaleDB hypertable report row counts and sizes that are wrong rather than missing, and YugabyteDB reports 0 until you run
ANALYZE. Vitess is not one of those three, its row counts and sizes being exact to the byte, but a running query cannot be cancelled there: vtgate refusesKILL QUERYand the statement runs to completion. AlloyDB Omni is not one of them either, reporting 2000 rows for 2000 and 270336 bytes for 270336, but two things there surprise:version()names AlloyDB nowhere, so the version panel cannot be told apart from a stock PostgreSQL 17, and eight of AlloyDB's owngoogle_mltables list in the object browser, which any role that can connect at all may also read. StarRocks reports itself as MySQL 5.1 and loses its overview, health and session panels, its monitoring dashboard rendering six panels with the session one carrying the engine's own refusal; Apache Doris - the engine StarRocks is a fork of - loses only the overview and health panels, to one statement form its grammar rejects, and is the more trustworthy of the two where it counts: it reports 2000 rows and 10187 bytes for a table holding exactly that, where StarRocks reads zero at first too - its own background statistics collector is slower, measured 4.5 minutes against 3.3.22 where Doris's is about a minute - and, until a 2026-09-16 fix, read zero forever afterward for sizes specifically, because StarRocks'INDEX_LENGTHis NULL rather than Doris's real 0 and poisoned the sum the provider computed in SQL; no index is ever reported, and a foreign key is accepted, listed bySHOW CONSTRAINTS, invisible to the ER diagram and unenforced; Cloudberry loses the monitoring dashboard and its table and index statistics, all three to one MPP planner restriction, and reads a foreign key back as though it were enforced when it is not, though its row counts are correct; CockroachDB loses the object browser and the size panels; OceanBase answers fourteen of the fifteen surfaces but only twelve of them usefully, health failing outright because its tenant has noperformance_schemadatabase at all and every size reading 0 B, though its row counts are correct onceANALYZE TABLEhas run; SingleStore lost five surfaces to a cause that was ours rather than its own - the provider sent every statement through the prepared-statement protocol, which SingleStore refuses for theSHOWandEXPLAINstatements four panels need - and four of those five are now recovered, its Explain panel being the one that is not, because there the grammar wantsEXPLAIN JSONand the statement fails on either protocol; its numbers are still missing rather than wrong, a 2000-row table reading 0 rows and 0 B with noANALYZEable to change it; ScyllaDB loses five surfaces and Test Connection with them, all six to one absent keyspace - the overview, health, performance-metrics, active-session and monitoring panels read Cassandra'ssystem_viewsvirtual tables and ScyllaDB has nosystem_viewskeyspace at all - those five now degrade to empty rather than throwing, so Test Connection passes and the dialog saves the connection, which it could not do at all until that change - while the editor and the object browser work in full, every one of 18 CQL types reading back byte-identically to the Cassandra 5.0.9 probed in the same pass; ParadeDB and OrioleDB are both full and their costs are opposites: ParadeDB's nine extensions put 41 objects in the object browser for 2 user tables, though agent plan mode works there under a least-privilege role and is refused only as thepostgressuperuser, as on any PostgreSQL, while OrioleDB's browser is clean and its own storage is invisible to PostgreSQL's size functions, so every index reads 0 bytes and the cache hit ratio reads N/A. Materialize and RisingWave are partial: the object browser shows their tables, views and materialized views with their columns, while row counts, sizes and the monitoring statistics stay blank. Garnet behaves as Redis and is one of three relatives here (with Valkey and DragonflyDB) whose own versionINFOcarries beside the Redis compat level and the overview now labels ahead of it -Garnet 2.1.5 (Redis 7.4.3)- and two of its readings are absences wearing a value, every size showing 0 B because it publishes noused_memoryand the cache hit ratio showing 100% because it publishes no keyspace counters. VictoriaMetrics runs PromQL through the Prometheus driver and lists its metrics with their label columns, its targets, and up to fifty of its metrics with the most series, but its rule folders are empty, because a single-node server evaluates no rules; the overview, the storage statistics and the scrape pool folder fail, because it does not serve three of the Prometheus endpoints they read; a metric's source shows no unit and a target's no scrape interval or timeout, because it sends none, and a target it has not scraped yet reads as down; and a string expression returns no rows, a subquery's points are counted back from its evaluation time, and no PromQL info or warning appears beside any result. Redpanda answers every Kafka surface through the Apache Kafka driver, its topics, consumer groups with their lag, brokers and reads alike, but its overview reads max connections as 0 and its broker source lists nine configs, because a broker's config answer holds only those, its storage statistics carry no usage percentage, and every group reads as classic, which is right there, since Redpanda has no other group protocol. The per-engine detail, with the exact version probed, is indocs/providers/README.md: we publish a name only after connecting to it, so a name absent there is untested rather than unsupported.
Transport security is cross-cutting, not per engine. The SSH tunnel is opened before the provider connects and the connection is rewritten to the local endpoint, so it is provider-independent: it applies to any connection configured with a host and a port, except a Kafka connection, which refuses one because a Kafka client reaches every broker at the address the broker advertises, which a tunnel to one address does not carry. A connection entered as a connection string instead (an option for MongoDB, Couchbase, ClickHouse and libSQL) carries neither, so it is not tunnelled; SQLite and DuckDB have neither either. The SSL/TLS panel is honoured by every engine that shows it, which is every engine except the three file-based ones, SQLite, DuckDB and the embedded LibreDB, where no transport exists to secure and no panel is offered. On Trino it is load-bearing rather than optional, because the coordinator refuses a password over plain HTTP. Oracle is the one engine whose mapping carries a caveat worth stating up front: its Thin driver always verifies
