Skip to main content

MySQL

Databases Analytics

Synopsis​

Creates a MySQL target that writes records into one table of an existing MySQL or MariaDB database. Each field of a record fills the column with the same name, or the whole record goes into a single JSON column.

Schema​

- name: <string>
description: <string>
type: mysql
pipelines: <pipeline[]>
status: <boolean>
properties:
address: <string>
port: <integer>
database: <string>
table: <string>
username: <string>
password: <string>
json_column: <string>
batch_size: <integer>
max_bytes: <integer>
timeout: <integer>
field_format: <string>
tls:
status: <boolean>
verify: <boolean>
ca_name: <string>
cert_name: <string>
key_name: <string>
passphrase: <string>
server_name: <string>
min_tls_version: <string>
max_tls_version: <string>
debug:
status: <boolean>
dont_send_logs: <boolean>

Configuration​

The following fields are used to define the target:

FieldRequiredDefaultDescription
nameYTarget name
descriptionN-Optional description
typeYMust be mysql
pipelinesN-Optional post-processor pipelines
statusNtrueEnable/disable the target

Connection​

FieldRequiredDefaultDescription
addressY-Host name or IP address of the MySQL or MariaDB server
portN3306Port of the server
databaseY-The database that holds the table. MySQL has no schema level, so the database takes its place
usernameN-The user that writes to the table. It needs permission to insert into it
passwordN-Password for that user
timeoutN30Seconds one database call may take. At least 1

Table​

FieldRequiredDefaultDescription
tableY-The table to write to. It must already exist
json_columnN-The column that receives the whole record. A json, varchar or text column. Leave it out to fill columns by name. See Columns by Name or Whole Record as JSON

The schema key that the other SQL targets take is ignored here.

The database, table and JSON column names must start with a letter or an underscore, and use only letters, digits and underscores. Any other name is refused and the target does not start.

Delivery​

FieldRequiredDefaultDescription
batch_sizeN1000The most records in one write. The target's own value first, then the service-level batch_size, then 1000
max_bytesN16777216 (16 MiB)The most bytes of JSON in one write
field_formatN-Converts each record to a format such as ECS or OCSF before it is written. See applicable Normalization section
note

max_bytes caps the size of a single request body or batch. It behaves differently from max_size on the file-writing targets, and the difference is easy to get wrong:

  • An explicit max_bytes: 0 IS honoured and removes the ceiling on targets that have no ceiling of their own. The value is read with Int64, which returns what you wrote — unlike max_size, which is read with MustInt64 and silently substitutes its default for a zero. Where a target has a fixed ceiling of its own, its page says so and a zero is clamped to that ceiling instead.
  • A negative value is rejected at configuration time with max_bytes must not be negative.

The ceiling is validated when the target is built and enforced again on every batch, so a value the receiving service will refuse fails early rather than per request.

TLS​

FieldRequiredDefaultDescription
tls.statusNfalseConnect over TLS. TLS stays off unless this is true

TLS material is resolved through the shared client builder, so these keys mean the same thing on every target that uses it. They are nested under a tls: block.

FieldRequiredDefaultDescription
tls.verifyNtrueVerify the server certificate. On by default — set it to false only to accept an untrusted certificate, and only where you control the network path
tls.server_nameN-SNI hostname override for the handshake. Use it when the certificate's name does not match the address you connect to
tls.ca_nameN-CA bundle used to verify the server certificate. When unset the host trust store is used; when set it replaces the host trust store rather than adding to it
tls.cert_nameN*-Client certificate, for mutual TLS
tls.key_nameN*-Client private key, for mutual TLS
tls.passphraseN-Passphrase for an encrypted client private key
tls.min_tls_versionNtls1.2Lowest protocol version accepted (tls1.0, tls1.1, tls1.2, tls1.3)
tls.max_tls_versionNtls1.3Highest protocol version accepted (tls1.0, tls1.1, tls1.2, tls1.3)

* cert_name and key_name are individually optional but must be supplied together — a certificate without its key, or a key without its certificate, is a configuration error.

Scheduling​

See Scheduling and Pool Behavior for interval and cron fields shared by all targets.

Debug Options​

FieldRequiredDefaultDescription
debug.statusNfalseEnable debug logging
debug.dont_send_logsNfalseProcess logs but don't send to target (testing)

Details​

The MySQL target writes records into one table that already exists, on MySQL or on MariaDB. It never creates the table or changes it, and it only adds rows. Each batch is written in one go, and each worker uses its own connection to the database.

Columns by Name or Whole Record as JSON​

The target works in one of two modes:

  • Columns by name, the default: each top-level field of a record fills the column with the same name, with the same upper and lower case. A field with no matching column is skipped. A record that is not a JSON object, or that fills no column, is skipped and counted as dropped.
  • Whole record as JSON, when json_column is set: the whole record goes into that one column, and every other column keeps its default. A record that is not valid JSON is written as a JSON string.

The target leaves out generated columns, because MySQL refuses a value written to them.

warning

A field with no matching column is skipped without an error. If no field of a record matches any column, the record is dropped, and when a whole batch keeps nothing the Director logs a warning. Check the column names against the fields your pipeline emits before relying on the target.

Time Values and Strict SQL Mode​

The target runs its session in UTC. For a date or time column, a field that holds an RFC 3339 time with a time zone, such as 2026-10-14T03:00:00+03:00, is converted to UTC before it is written, so TIMESTAMP and DATETIME columns both receive the UTC time. A time without a time zone is passed on as written: a TIMESTAMP column reads it as UTC, and a DATETIME column stores it unchanged, with no conversion.

We recommend strict SQL mode on the server. Without it, the server does not refuse a value that is out of range for its column: it changes the value to the nearest value the column accepts, and the target cannot tell that it did.

Prerequisites​

  1. A running MySQL or MariaDB server, reachable from the Director host
  2. The database and the table, already created
  3. A user with permission to insert into the table

Examples​

Basic​

Writing each record's fields into the columns of the same name:

targets:
- name: mysql_events
type: mysql
properties:
address: "mysql.example.com"
database: "analytics"
table: "events"
username: "datastream"
password: "secret"

port is left out, so it defaults to 3306.

Whole Record as JSON​

Writing each whole record into a json column:

targets:
- name: mysql_raw
type: mysql
properties:
address: "mysql.example.com"
database: "analytics"
table: "raw_events"
json_column: "record"
username: "datastream"
password: "secret"

Every other column of the table keeps its default.

Troubleshooting​

SituationResult
The database refuses a value, for example one that does not fit its columnThe batch is sent again one record at a time. Only the records that still fail are dropped, and they are counted as dropped
The connection or the server has a temporary problemThe batch is retried
A column was removed from the tableThe target reads the table's columns again once and retries the batch
The table does not exist when the target startsThe target stops with an error. Create the table first and give the user access to it

The table was not found​

mysql table analytics.events was not found, or it has no columns this target can write. Create the table first, and give the user access to it

Cause: the table named in database and table does not exist, the user cannot see it, or every one of its columns is generated. The target reads the table's columns when it starts, so this shows up at startup rather than on the first batch.

Fix: create the table, or correct database and table, and grant the user access to it.

Records are dropped although nothing fails​

Cause: the fields of the records match no column of the table. Names match exactly, including case.

Fix: rename the columns after the fields your pipeline emits, or set json_column to store the whole record in one column.

Values arrive changed​

Cause: the server is not in strict SQL mode, so it changed an out-of-range value to the nearest value the column accepts instead of refusing it.

Fix: turn on strict SQL mode. The server then refuses such a value, and the target drops only that record and counts it as dropped.

Configuration errors​

These stop the target from starting:

Reason textFix
address is required for mysql targetSet address
database is required for mysql targetSet database
table is required for mysql targetSet table
invalid database name "..." for mysql targetUse a name of letters, digits and underscores that starts with a letter or an underscore. The same rule applies to table and json_column
timeout must be at least 1 second for mysql target, got ...Set timeout to 1 or more
batch_size must be a whole number greater than 0 for mysql target, got ...Use a whole number of at least 1, or leave batch_size out to use the service-level value
failed to build TLS config: ...The rest of the line names the TLS setting at fault