Logstash Error Guide: 'could not load driver class com.mysql.jdbc.Driver' — Fix the JDBC Input Driver
Fix Logstash jdbc input 'could not load driver class': set jdbc_driver_library and jdbc_driver_class correctly, verify the JAR path, and test it.
- #logstash
- #logging
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
The Logstash jdbc input plugin loads a database driver class by name at pipeline startup. When the JAR that contains that class is not on the classpath — or the class name is misspelled, or points at a driver that no longer exists in your connector version — the plugin throws a ClassNotFoundException and the pipeline never reaches the query stage. The most common form of this error looks like this in /var/log/logstash/logstash-plain.log:
[ERROR][logstash.inputs.jdbc][main][a1b2...] Unable to connect to database. Tried 1 times {:message=>"Java::JavaLang::ClassNotFoundException: com.mysql.jdbc.Driver"}
You will also see the closely related Sequel/JRuby wrapper message that names the same missing class:
[ERROR][logstash.javapipeline][main] Pipeline error {:pipeline_id=>"main", :exception=>#<Sequel::DatabaseConnectionError: Java::JavaLang::ClassNotFoundException: could not load driver class com.mysql.jdbc.Driver>}
In plain terms: Logstash asked the JVM to instantiate the driver class you named in jdbc_driver_class, and the JVM could not find a class by that name in any JAR it was told about via jdbc_driver_library. There are only two moving parts here — the library (the physical JAR) and the class (the fully-qualified name inside it) — and this error means at least one of them is wrong.
Symptoms
- The pipeline that owns the
jdbcinput fails to start, or starts and immediately logs aPipeline errorand shuts that pipeline down. logstash-plain.logshowsClassNotFoundExceptionnaming a driver class such ascom.mysql.jdbc.Driver,com.mysql.cj.jdbc.Driver,org.postgresql.Driver, ororacle.jdbc.OracleDriver.- No rows are ever emitted; downstream Elasticsearch indices stay empty even though the database is reachable from the host.
bin/logstash --config.test_and_exitpasses (the syntax is valid) but the pipeline still fails at runtime, because driver loading happens when the input starts, not during config parsing.- With MySQL Connector/J 8.x, the log names
com.mysql.jdbc.Driveras missing even though the JAR is present — because that class was renamed.
Common Root Causes
- Missing
jdbc_driver_library— the input block setsjdbc_driver_classbut never pointsjdbc_driver_libraryat a JAR, so the class is nowhere on the classpath. - Wrong path to the JAR —
jdbc_driver_librarypoints at a file that does not exist (typo, wrong directory, or a path only valid on the developer’s laptop). Logstash silently proceeds and only fails when the class cannot be found. - Renamed driver class in newer connectors — MySQL Connector/J 8.x replaced
com.mysql.jdbc.Driverwithcom.mysql.cj.jdbc.Driver. Configs copied from old tutorials still name the old class. - Misspelled or miscased class name — Java class names are case-sensitive and dotted exactly;
com.mysql.jdbc.driverororg.postgresql.driverwill not resolve. - Permissions on the JAR — the
logstashservice user cannot read the JAR (root-owned0600file), so the class fails to load even though the path is correct. - Corrupt or partial JAR download — a truncated connector JAR (interrupted
curl, wrong artifact) does not contain the driver class. - Relative path resolved from the wrong working directory —
jdbc_driver_library => "mysql-connector-j.jar"is resolved relative to Logstash’s runtime directory, not your config directory, and is not found.
Diagnostic Workflow
Start by validating that the configuration is syntactically sound. This does not load the driver, but it rules out a broken config file confusing the picture:
sudo -u logstash /usr/share/logstash/bin/logstash \
-f /etc/logstash/conf.d/mysql-jdbc.conf \
--config.test_and_exit --path.settings /etc/logstash
Then confirm the JAR actually exists, is readable by the service user, and contains the class you named:
# Does the file exist and can the logstash user read it?
sudo -u logstash test -r /usr/share/logstash/drivers/mysql-connector-j-8.4.0.jar && echo OK
# List the driver classes actually inside the JAR
unzip -l /usr/share/logstash/drivers/mysql-connector-j-8.4.0.jar | grep -i 'Driver.class'
For MySQL Connector/J 8.x you will see com/mysql/cj/jdbc/Driver.class — that dotted path (com.mysql.cj.jdbc.Driver) is exactly what belongs in jdbc_driver_class.
Here is a realistic, correct jdbc input block. Logstash .conf files use a Ruby-like DSL, so the config is shown as ruby:
input {
jdbc {
jdbc_driver_library => "/usr/share/logstash/drivers/mysql-connector-j-8.4.0.jar"
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://db.internal:3306/appdb?useSSL=false&serverTimezone=UTC"
jdbc_user => "logstash_ro"
jdbc_password => "${MYSQL_RO_PASSWORD}"
schedule => "*/5 * * * *"
statement => "SELECT id, email, updated_at FROM users WHERE updated_at > :sql_last_value"
use_column_value => true
tracking_column => "updated_at"
tracking_column_type => "timestamp"
last_run_metadata_path => "/var/lib/logstash/.jdbc_last_run_users"
}
}
output {
elasticsearch {
hosts => ["https://es.internal:9200"]
index => "app-users-%{+YYYY.MM.dd}"
document_id => "%{id}"
}
}
Finally, watch the log live while you start the pipeline so you catch the exact class name the JVM is missing:
sudo systemctl restart logstash
sudo tail -f /var/log/logstash/logstash-plain.log | grep -i 'ClassNotFound\|jdbc'
Example Root Cause Analysis
A team upgraded a Debian host and, as part of it, bumped the MySQL connector JAR from the old mysql-connector-java-5.1.47.jar to mysql-connector-j-8.4.0.jar. They updated jdbc_driver_library to the new path but left the rest of the block untouched. On restart the pipeline died immediately with ClassNotFoundException: com.mysql.jdbc.Driver.
The config was valid — --config.test_and_exit returned Configuration OK. So the syntax was not the problem. Running unzip -l on the new JAR was decisive:
$ unzip -l mysql-connector-j-8.4.0.jar | grep -i Driver.class
1234 2024-04-25 10:12 com/mysql/cj/jdbc/Driver.class
The class shipped in 8.x is com.mysql.cj.jdbc.Driver — note the extra .cj. segment. The legacy com.mysql.jdbc.Driver was removed in Connector/J 8. The config still named the old class, so the JVM correctly reported it could not find it, even though a perfectly good driver JAR was on the classpath.
The fix was a one-line change:
# before
jdbc_driver_class => "com.mysql.jdbc.Driver"
# after
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
After restarting, logstash-plain.log showed the scheduled statement executing and rows flowing into the app-users-* index. The lesson: a passing config test only proves the syntax is valid; the driver class is verified against the JAR at runtime, so always confirm the class name matches what unzip -l reports inside the exact JAR you deployed.
Prevention Best Practices
- Pin the connector JAR to an absolute, version-stamped path (
/usr/share/logstash/drivers/mysql-connector-j-8.4.0.jar) and reference that same path injdbc_driver_library— never a bare filename. - Whenever you upgrade a database connector, re-derive
jdbc_driver_classfromunzip -l … | grep Driver.classrather than copying it from an older config or a blog post. - Keep driver JARs owned by, and readable by, the
logstashservice user; store them outside the config directory so a config redeploy never removes them. - Use environment variables (
${MYSQL_RO_PASSWORD}) for credentials via the Logstash keystore orssr.env-style secrets, so the connection string in Git never carries a password. - Standardize on the current driver class per database: MySQL 8.x →
com.mysql.cj.jdbc.Driver, PostgreSQL →org.postgresql.Driver, Oracle →oracle.jdbc.OracleDriver, SQL Server →com.microsoft.sqlserver.jdbc.SQLServerDriver. - Bake the JAR and its path into your image build or configuration-management role, and add a smoke test that greps the pipeline log for
ClassNotFoundafter every deploy.
Quick Command Reference
# Validate config syntax (does not load the driver)
sudo -u logstash /usr/share/logstash/bin/logstash \
-f /etc/logstash/conf.d/mysql-jdbc.conf \
--config.test_and_exit --path.settings /etc/logstash
# List the actual driver classes inside a connector JAR
unzip -l /usr/share/logstash/drivers/mysql-connector-j-8.4.0.jar | grep -i 'Driver.class'
# Confirm the logstash user can read the JAR
sudo -u logstash test -r /usr/share/logstash/drivers/mysql-connector-j-8.4.0.jar && echo readable
# Watch for the exact missing-class error at startup
sudo tail -f /var/log/logstash/logstash-plain.log | grep -i 'ClassNotFound\|jdbc'
# Restart the service and follow status
sudo systemctl restart logstash && sudo systemctl status logstash --no-pager
Conclusion
ClassNotFoundException / could not load driver class from the Logstash jdbc input is almost always one of two things: the JAR named by jdbc_driver_library is missing or unreadable, or the name in jdbc_driver_class does not match the class that actually ships inside that JAR. Verify the file with test -r, list its classes with unzip -l, and set jdbc_driver_class to the exact dotted path you find — most often com.mysql.cj.jdbc.Driver for modern MySQL. Because driver loading happens at runtime rather than during --config.test_and_exit, always confirm the fix by tailing logstash-plain.log after a restart and watching the scheduled query run.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.