Setup
- Open Settings → Lake and choose Add MySQL connection.
- Paste a
mysql://URL to fill the fields automatically, or enter them by hand:
The dialog generates the SQL for a read-only user if you want to create one - copy it and run it against your database before saving:
Querying live
A connection is scoped to one database, so tables are reachable asconnection_name.database.table:
information_schema with primary key columns marked.
A MySQL table selects DuckDB. DuckDB is the only engine that attaches external connections, so the query router routes any query naming a connection table there before it considers input size - leave
engine on auto. Asking for Bloom, Polars, or Spark on one of these queries returns an engine capability error rather than rerouting silently.Importing into Iceberg
For anything larger than an ad hoc read, import the table. The import runs as a Spark JDBC read and lands the data as an Iceberg table in your lake, where every engine can reach it.- The read is split into parallel ranges over the table’s integer primary key, with the partition count following table size. A table without an integer primary key is read on a single connection.
DATETIMEvalues keep their wall-clock time, and zero dates (0000-00-00) are read asNULL.
Unlike Postgres imports, MySQL cannot share one snapshot across connections, so a parallel import of a live, changing table is not guaranteed to be consistent across partitions. Import from a replica, or during a quiet period, when that matters.
oleander.default.<table> - the sanitized source table name, with no connection prefix. OVERWRITE replaces it, APPEND adds to it.
An import does not return rows. It submits a job and returns a run_id you can monitor like any other run, and once it completes you can sample the destination with a normal query.
Table syncing
A one-off import gives you a snapshot. Put the same import on a schedule and the Iceberg copy tracks the source instead. Schedules run hourly or daily, and are managed the same way as Postgres syncs: under Scheduled syncs in Settings → Lake, and under Transfers in the lake’s left panel.Scheduled syncs are incremental where the table allows it. After the first full import, each run picks up new and changed rows rather than recopying the table.
Every sync run is a normal oleander run: it appears in run history, emits lineage with the MySQL table as the input and the Iceberg table as the output, and carries cost like any other job.
From an agent
Two tools cover MySQL over MCP:
For ad hoc reads of live data an agent uses
query_run against connection.database.table instead.