A Logstash JDBC input turns rows from a relational database into pipeline events without staging CSV exports or writing a separate poller. Regular polling keeps operational or application data moving into downstream pipelines while the database remains the source of truth.
The jdbc input plugin loads a vendor JDBC driver jar, connects through a JDBC URL, runs a SQL statement, and converts each returned row into a Logstash event. Incremental polling uses sql_last_value, which is written to a metadata file so later runs resume from the previous checkpoint instead of starting from the beginning.
Current Logstash releases do not bundle JDBC drivers, and a custom last_run_metadata_path only works when its parent directory already exists and is writable by the logstash service user. On package-based Linux installs, keeping the driver jar, password file, and checkpoint file in predictable paths makes pipeline validation and service restarts much easier.
Related: How to create a Logstash keystore
Related: How to add a secret to a Logstash keystore
$ sudo install -d -m 0755 /usr/share/logstash/vendor/jdbc $ sudo install -m 0644 postgresql.jar /usr/share/logstash/vendor/jdbc/postgresql.jar
The JDBC input does not ship with database drivers. Replace the jar name, jdbc_driver_library, jdbc_driver_class, and jdbc_connection_string with the values for MySQL, MariaDB, SQL Server, Oracle, or another supported JDBC source when needed.
$ sudo install -o root -g logstash -m 0750 -d /etc/logstash/secrets /var/lib/logstash/jdbc_last_run $ printf '%s\n' 'db-reader-password' | sudo tee /etc/logstash/secrets/jdbc-orders.pwd >/dev/null $ sudo chown root:logstash /etc/logstash/secrets/jdbc-orders.pwd $ sudo chmod 0640 /etc/logstash/secrets/jdbc-orders.pwd
If last_run_metadata_path points to a custom file, its parent directory must exist before the pipeline starts or the JDBC scheduler can query successfully but fail when it tries to write the checkpoint.
A password file keeps the secret out of the pipeline definition. Use the Logstash keystore instead when the service already relies on keystore-backed substitutions.
input {
jdbc {
id => "jdbc_orders"
jdbc_driver_library => "/usr/share/logstash/vendor/jdbc/postgresql.jar"
jdbc_driver_class => "org.postgresql.Driver"
jdbc_connection_string => "jdbc:postgresql://db.example.net:5432/app"
jdbc_user => "logstash"
jdbc_password_filepath => "/etc/logstash/secrets/jdbc-orders.pwd"
period => "1m"
statement => "SELECT id, customer_email, updated_at FROM orders WHERE updated_at > :sql_last_value ORDER BY updated_at ASC, id ASC"
use_column_value => true
tracking_column => "updated_at"
tracking_column_type => "timestamp"
jdbc_validate_connection => true
jdbc_validation_timeout => 50
last_run_metadata_path => "/var/lib/logstash/jdbc_last_run/orders.yml"
}
}
output {
stdout {
codec => json_lines
}
}
Use schedule with a cron expression such as */5 * * * * UTC when the poll must align to wall-clock times. Keep period when only a fixed interval matters, or omit both lines to run the statement once at startup.
The stdout output is useful for the first successful poll because it proves the JDBC input is emitting events before another destination is added. Replace it with the target output after validation. Related: How to configure Logstash output to Elasticsearch
$ sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash --path.data /tmp/logstash-configtest --config.test_and_exit
Using bundled JDK: /usr/share/logstash/jdk
[2026-04-08T00:00:04,469][INFO ][logstash.runner ] Starting Logstash {"logstash.version"=>"9.3.1"}
##### snipped #####
Configuration OK
[2026-04-08T00:00:08,208][INFO ][logstash.runner ] Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash
The temporary --path.data directory keeps the syntax check away from the running service state in /var/lib/logstash.
$ sudo systemctl restart logstash
$ curl -s http://localhost:9600/_node/stats/pipelines/main?pretty=true
{
"pipelines" : {
"main" : {
"events" : {
"in" : 3,
"filtered" : 3,
"out" : 3
},
"plugins" : {
"inputs" : [ {
"id" : "jdbc_orders",
"name" : "jdbc",
"events" : {
"out" : 3
}
} ]
}
}
}
}
The monitoring API binds to 127.0.0.1 by default on package installs. If the API is secured or moved to another address or port, query the configured endpoint instead.
$ sudo cat /var/lib/logstash/jdbc_last_run/orders.yml --- 2026-04-08 00:14:00.000000000 Z
If the SQL query is running but the checkpoint file never appears, re-check the parent directory named in last_run_metadata_path and make sure the logstash service user can write to it.