Skip to main content
clickhouse-jdbc implements the standard JDBC interface using the latest java client. We recommend using the latest java client directly if performance/direct access is critical.

Environment requirements

Setup

If you are using JDBC driver within an application that requires jar to be added to the classpath, you need to add download the jar from:

Configuration

Driver Class: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriver is a facade class for the new and old JDBC implementations. It uses the new JDBC implementation by default. You can use the old JDBC implementation by setting the clickhouse.jdbc.v1 system property to true. This property should be set before calling Driver class.Alternative way to switch between version is to use Driver classes of each version directly:
  • com.clickhouse.jdbc.Driver is new JDBC implementation (V2).
  • com.clickhouse.jdbc.DriverV1 is old JDBC implementation (V1).
URL Syntax: jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1&param2=value2][#tag1,tag2,...], for example:
  • jdbc:clickhouse:http://localhost:8123
  • jdbc:clickhouse:https://localhost:8443?ssl=true
There are a few things to note about the URL syntax:
  • only one endpoint is allowed in the URL
  • protocol should be specified when it isn’t the default one - ‘HTTP’
  • port should be specified when it isn’t the default one ‘8123’
  • driver don’t guess the protocol from the port, you need to specify it explicitly
  • ssl parameter isn’t required when protocol is specified.

Connection Properties

Main configuration parameters are defined in the java client. They should be passed as is to the driver. Driver has some own properties that aren’t part of the client configuration they’re listed below.Driver properties:
Server SettingsAll server settings should be prefixed with clickhouse_setting_ (same as for the client configuration).
Example configuration:
what will be equivalent to the following JDBC URL:
Note: no need to url encode JDBC URL or properties, they will be automatically encoded.Readonly ProfilesWe deliberately avoid adding default settings to connection properties to avoid problems with read-only profiles. However some users need to pass format settings (for example to read JSON as String) and we recommend using readonly=2 profile. Read more about read-only profiles here.

Client Identification

There are two ways to identify application originated a request: set com.clickhouse.client.api.ClientConfigProperties#CLIENT_NAME via connection properties or use java.sql.Connection#setClientInfo(String name, String value) method.
showLineNumbers
showLineNumbers
Both ways will result in the following http_user_agent value in the query log:
Note: We recommend using app_name/version format for client_name property because it helps to identify the application in the query log.

Operation Identification

JDBC driver generates query_id for each operation (Currently it is included in server exceptions).To set log_comment for an operation use com.clickhouse.jdbc.StatementImpl#getLocalSettings method. This requires Statement or PreparedStatement to be cast to com.clickhouse.jdbc.StatementImpl first.
showLineNumbers
Note: this approach work for single threaded uses of statement because localSettings is shared between threads.

Supported data types

JDBC driver supports the same data formats as the underlying java client.

JDBC Type Mapping

Following mapping applies to:
  • ResultSet#getObject(columnIndex) - method will return object of the corresponding Java class. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
  • ResultSetMetaData#getColumnType(columnIndex) - method will return the corresponding JDBC type. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
There are few ways to change the mapping:
  • ResultSet#getObject(columnIndex, class) - method will try to convert value to class type. There are some conversion limitations. See each section for details.
Numeric Types
  • numeric types are interconvertible. So Int8 can be get as Float64 and vice versa.:
    • rs.getObject(1, Float64.class) will return Float64 value of Int8 column.
    • rs.getLong(1) will return Long value of Int8 column.
    • rs.getByte(1) can return Byte value of Int16 column if it fits into Byte.
  • conversion from wider to narrower type isn’t recommend because of data coruption risk.
  • Bool type acts as number, too.
  • All number types can be read as java.lang.String.
  • Storing java Float.MAX_VALUE as Float has issue (https://github.com/ClickHouse/clickhouse-java/issues/809). Saving same value as Double solves the issue.
String Types
  • String can be read only as java.lang.String or byte[].
  • FixedString is read as is and will be padded with zeros to the length of the column. (For example FixedString(10) for 'John' will be read as 'John\0\0\0\0\0\0\0\0\0'.)
Enum Types
  • Enum8 and Enum16 are mapped to java.lang.String by default.
  • Enum values can be read as numeric values using designtated getter method or getObject(columnIndex, Integer.class) method.
  • Enum16 is mapped to short and Enum8 is mapped to byte internally. Reading Enum16 as byte should be avoided because of data coruption risk.
  • Enum values can be set as string or numeric value in PreparedStatement.
Date/Time Types
  • Date / Time types are mapped to java.sql types for better compatibility with JDBC. However getting java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime is possible by using ResultSet#getObject(columnIndex, Class<T>) with the corresponding class as the second argument.
    • rs.getObject(1, java.time.LocalDate.class) will return java.time.LocalDate value of Date column.
    • rs.getObject(1, java.time.LocalDateTime.class) will return java.time.LocalDateTime value of DateTime column.
    • rs.getObject(1, java.time.LocalTime.class) will return java.time.LocalTime value of Time column.
  • Date, Date32, Time, Time64 isn’t affected by the timezone of the server.
  • DateTime, DateTime64 is affected by the timezone of the server or session timezone.
  • DateTime and DateTime64 can be retrieved as ZonedDateTime by using getObject(colIndex, ZonedDateTime.class).
Nested Types
  • Array is mapped to java.sql.Array by default to be compatible with JDBC. This is also done to give more information about returned array value. Useful for type inference.
  • Array implements getResultSet() method to return java.sql.ResultSet with the same content as the original array.
  • Collection types shouldn’t be read as java.lang.String because it isn’t a valid way to represent the data (Ex. there is no quoting for string values in array).
  • Map is mapped to OTHER because value can be read only with getObject(columnIndex, Class<T>) method.
    • Map isn’t a java.sql.Struct because it doesn’t have named columns.
  • Tuple is mapped to Object[] because it can contain different types and using List isn’t valid.
  • Tuple can be read as Array by using getObject(columnIndex, Array.class) method. In this case Array#baseTypeName will return Tuple column definition.
Array Element Type MetadataArray.getBaseTypeName() returns the ClickHouse element type name; Array.getBaseType() returns the JDBC type code. JDBC V2 preserves full type signatures (wrapper types, type parameters) that V1 strips.The general mapping rules for arrays are:Notes on the rules above:
  • Wrapper types (Nullable, LowCardinality) are preserved in getBaseTypeName() but getBaseType() resolves to the inner type’s JDBC code.
  • Nested arrays are flattened in the metadata: getBaseTypeName() returns the innermost non-array element type, not the immediate child.
  • Parameterized types (FixedString(N), full Enum/Tuple definitions) keep their parameters in getBaseTypeName().
Examples:
  • In V2, getBaseTypeName() preserves the full type signature including wrapper types (Nullable, LowCardinality) and type parameters (FixedString(8), full Enum and Tuple definitions). V1 strips these and returns only the base type name.
  • Tuple arrays use OTHER (1111) in V2 instead of STRUCT (2002) because ClickHouse tuples have named fields, which java.sql.Struct does not support.
  • UUID arrays use OTHER (1111) in V2, matching the scalar UUID mapping.
  • Enum values map to VARCHAR — enum members are identified by string name regardless of their underlying numeric encoding.
Writing ArraysUse java.sql.Connection#createArrayOf to instantiate java.sql.Array object. This object is designed to make array handling unified across different databases. Connection is required to pass configuration to Array factory method.The method accepts two arguments:
  • typeName - type name of the array elements. For example Array(Int32) -> "Int32".
  • elements - actual array elements. For example [[1, 2, 3], [4, 5, 6]] -> new Integer[][] {{1, 2, 3}, {4, 5, 6}}.
Tuple can be presented as Object[] or as java.sql.Struct (See how to write tuples bellow).Example
Reading ArraysUse ResultSet#getArray(columnIndex) to read Array object. Object can be used to access array of any nested depth. Array#getResultSet() method can be used to read array elements in more unified way as java.sql.ResultSet. It is useful when exact type of array elements is unknown.Example
Writing TuplesTuples are mapped to com.clickhouse.data.Tuple object and should be written as this object by calling setObject(columnIndex, tuple) method. It is possible to use java.sql.Struct object to write tuples for better portability.Example
Reading TuplesThe method getObject(columnIndex) will return Object[]. Tuples can be read as java.sql.Array by using getObject(columnIndex, Array.class) method.Example
Writing MapsMap can be written only as java.collections.Map object because this types requires key-value pairs (java.sql.Struct doesn’t support key-value pairs).Example
Reading MapsMap can be read as java.collections.Map object by using getObject(columnIndex, Map.class) method.Example
Writing NestedUse java.sql.Connection#createStruct to instantiate java.sql.Struct object. This object is designed to make nested handling unified across different databases. Connection is required to pass configuration to Struct factory method.The method accepts two arguments:
  • typeName - type name of the nested elements. For example Nested(Tuple(Int32, String)) -> "Nested(Tuple(Int32, String))".
  • elements - actual nested elements. For example [1, 'test'] -> new Object[] {1, 'test'}.
Example
Reading NestedUse ResultSet#getStruct(columnIndex, StructDescriptor) to read Nested object. Object can be used to access nested of any nested depth. Struct#getResultSet() method can be used to read nested elements in more unified way as java.sql.ResultSet. It is useful when exact type of nested elements is unknown.Example
Geo TypesNullable and LowCardinality Types
  • Nullable and LowCardinality are special types that wrap other types.
  • Nullable affects how type names are returned in ResultSetMetaData
Special Types
  • UUID isn’t JDBC standard type. However it is part of JDK. By default java.util.UUID is returned on getObject() method.
  • UUID can be read/written as String by using getObject(columnIndex, String.class) method.
  • IPv4 and IPv6 aren’t JDBC standard types. However they’re part of JDK. By default java.net.Inet4Address and java.net.Inet6Address are returned on getObject() method.
  • IPv4 and IPv6 can be read/written as String by using getObject(columnIndex, String.class) method.
JSON TypeJSON type is mapped to Map<String, Object> by default where keys are JSON object keys and values are JSON object values. For example:
will be mapped to:
There is more convinient option to read JSON as String by passing server setting jdbc_read_json_as_string=true to connection properties. This makes driver return JSON values as String and can be used to parse using any JSON library.
Starting ClickHouse version 25.8 numbers are no longer quoted by default. For older versions you can disable quoting by passing server settings to connection properties:

Handling Dates, Times, and Timezones

Please read Date/Time Guide that explains common pitfalls and logic of the driver when handling Date/Time and Timestamps.

Creating Connection

Supplying Credentials and Settings

showLineNumbers

Simple Statement

showLineNumbers

Insert

showLineNumbers

HikariCP

showLineNumbers

More Information

For more information, see our GitHub repository and Java Client documentation.

Troubleshooting

Logging

The driver uses slf4j for logging, and will use the first available implementation on the classpath.

Resolving JDBC Timeout on Large Inserts

When performing large inserts in ClickHouse with long execution times, you may encounter JDBC timeout errors like:
These errors can disrupt the data insertion process and affect system stability. To address this issue you may need to adjust a few timeout settings in the client’s OS.

Mac OS

On Mac OS, the following settings can be adjusted to resolve the issue:
  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1

Linux

On Linux, the equivalent settings alone may not resolve the issue. Additional steps are required due to the differences in how Linux handles socket keep-alive settings. Follow these steps:
  1. Adjust the following Linux kernel parameters in /etc/sysctl.conf or a related configuration file:
  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1
  • net.ipv4.tcp_keepalive_intvl: 75
  • net.ipv4.tcp_keepalive_probes: 9
  • net.ipv4.tcp_keepalive_time: 60 (You may consider lowering this value from the default 300 seconds)
  1. After modifying the kernel parameters, apply the changes by running the following command:
After Setting those settings, you need to ensure that your client enables the Keep Alive option on the socket:

Migration Guide

Key Changes

  • JDBC V2 is implemented to be more lightweight and some features were removed.
    • Streaming Data isn’t supported in JDBC V2 because it isn’t part of the JDBC spec and Java.
  • JDBC V2 expects explicit configuration. No failover defaults.
    • Protocol should be specified in the URL. No implicit protocol detection using port numbers.

Configuration Changes

There are only two enums:
  • com.clickhouse.jdbc.DriverProperties - the driver own configuration properties.
  • com.clickhouse.client.api.ClientConfigProperties - the client configuration properties. Client configuration changes are described in the Java Client documentation.
Connection properties are parsed in the following way:
  • URL is parsed first for properties. They override all other properties.
  • Driver properties aren’t passed to the client.
  • Endpoints (host, port, protocol) are parsed from the URL.
Example:

Data Types Changes

Numeric Types
  • The biggest differences is that unsigned types are mapped to java types for better portability.
String Types
  • FixedString is read as is in both versions. For example FixedString(10) for 'John' will be read as 'John\0\0\0\0\0\0\0\0\0'.
  • When PreparedStatement#setBytes is used it will be converted to unhex('<hex_string>') and then read as String.
  • Strings are stored in UTF-8 encoding.
Date/Time Types
  • Time and Time64 are supported in V2 only as new types.
  • DateTime and DateTime64 are mapped to java.sql.Timestamp for better compatibility with JDBC.
Enum TypesNested Types
  • In V2 Array is mapped to java.sql.Array by default to be compatible with JDBC. This is also done to give more information about returned array value. Useful for type inference.
  • In V2 Array implements getResultSet() method to return java.sql.ResultSet with the same content as the original array.
  • V1 uses STRUCT for Map but returns java.util.Map object always. V2 fixes this by mapping Map to JAVA_OBJECT.
  • V1 uses STRUCT for Tuple but returns List<Object> object always. V2 maps Tuple to OTHER and returns Object[] by default.
  • V2 introduces com.clickhouse.data.Tuple#Tuple to write tuples. It simplifies determining if value is a tuple or and array.
  • PreparedStatement#setBytes and ResultSet#getBytes cannot be used with collection types. These methods are designed to work with binary strings.
  • Normally java.sql.Array is used to write and read Array types. JDBC driver has full support for this.
  • V2 Nested is mapped to Array and presents it as array of tuples.
  • V2 has partial support for java.sql.Struct because it very similar to Array type and doesn’t support key-value pairs. Struct can be used to write Tuple values.
Geo TypesNullable and LowCardinality Types
  • Nullable and LowCardinality are special types that wrap other types.
  • No changes are made to these types in V2.
Special Types
  • V1 uses VARCHAR for UUID but returns java.util.UUID object always. V2 fixes this by mapping UUID to OTHER and returns java.util.UUID object.
  • V1 uses VARCHAR for IPv4 and IPv6 but returns java.net.Inet4Address and java.net.Inet6Address objects always. V2 fixes this by mapping IPv4 and IPv6 to OTHER and returns java.net.Inet4Address and java.net.Inet6Address objects.
  • Dynamic and Variant are new types in V2. Not supported in V1.
  • JSON is based on Dynamic type. Therefore it is supported only in V2.
  • IPv4 and IPv6 values can be read as byte[] by using getBytes(columnIndex) method. However it is recommended to use designated classes for these types.
  • V2 do not support reading IP address as numeric values because convertion is better implementation in InetAddress classes.

Database Metadata Changes

  • V2 uses only Schema term to name databases. Catalog term is reserved for future use.
  • V2 returns false for DatabaseMetaData.supportsTransactions() and DatabaseMetaData.supportsSavepoints(). This will be changed in the future development.
  • In DatabaseMetaData.getTypeInfo(), the LITERAL_PREFIX and LITERAL_SUFFIX columns now return null for data types where prefixes and suffixes are not expected (e.g., numeric types). In V1, these columns returned non-null values for such types. These columns should be used when generating SQL queries to properly quote literal values according to their data type.
Last modified on June 23, 2026