Advanced connection information

Connection URI

The driver supports connection to URIs of the form

<SCHEME>://<HOST>[:<PORT>[?policy=<POLICY-NAME>]]
  • <SCHEME> is one among neo4j, neo4j+s, neo4j+ssc, bolt, bolt+s, bolt+ssc.

  • <HOST> is the host name where the Neo4j server is located.

  • <PORT> is optional, and denotes the port the Bolt protocol is available at.

  • <POLICY-NAME> is an optional server policy name. Server policies need to be set up prior to usage.

The driver does not support connection to a nested path, such as example.com/neo4j/. The server must be reachable from the domain root.

Connection protocols and security

Communication between the driver and the server is mediated by Bolt. The scheme of the server URI determines whether the connection is encrypted and, if so, what type of certificates are accepted.

URL scheme Encryption Comment

neo4j

Default for local setups

neo4j+s

(only CA-signed certificates)

Default for Aura

neo4j+ssc

(CA- and self-signed certificates)

The driver receives a routing table from the server upon successful connection, regardless of whether the instance is a proper cluster environment or a single-machine environment. The driver’s routing behavior works in tandem with Neo4j’s clustering by directing read/write transactions to appropriate cluster members. If you want to target a specific machine, use the bolt, bolt+s, or bolt+ssc URI schemes instead.

The connection scheme to use is not your choice, but is rather determined by the server requirements. You must know the right server scheme upfront, as no metadata is exposed prior to connection. If you are unsure, ask the database administrator.

Authentication methods

Basic authentication (default)

The basic authentication scheme relies on traditional username and password. These can either be the credentials for your local installation, or the ones provided with an Aura instance.

// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;

GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword));

The basic authentication scheme can also be used to authenticate against an LDAP server (Enterprise Edition only).

Kerberos authentication

The Kerberos authentication scheme requires a base64-encoded ticket. It can only be used if the server has the Kerberos Add-on installed.

// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;

GraphDatabase.driver(dbUri, AuthTokens.kerberos(ticket));

Bearer authentication

The bearer authentication scheme requires a base64-encoded token provided by an Identity Provider through Neo4j’s Single Sign-On feature.

// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;

GraphDatabase.driver(dbUri, AuthTokens.bearer(ticket));
The bearer authentication scheme requires configuring Single Sign-On on the server. Once configured, clients can discover Neo4j’s configuration through the Discovery API.

Custom authentication

Use AuthTokens.custom() to log into a server having a custom authentication scheme.

// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;

GraphDatabase.driver(dbUri, AuthTokens.custom(principal, credentials, realm, scheme, parameters));

No authentication

If authentication is disabled on the server, the authentication parameter can be omitted entirely.

Rotating authentication tokens

It is possible to rotate authentication tokens that are expected to expire (e.g. SSO). You need to provide a AuthTokenManager instance when instantiating the Driver, rather than a static authentication token.

The easiest way to get started is to use one of built-in AuthTokenManager implementations. AuthTokenManagers work with AuthToken objects.

Rotating a bearer token expiring every 60 seconds
// import java.time.Clock;
// import java.util.concurrent.TimeUnit;
// import org.neo4j.driver.AuthTokenManagers;
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;

void rotatingBearerDriver() {
    var tokenManager = AuthTokenManagers.bearer(() -> {
        var token = AuthTokens.bearer(getToken());

        // Assume we know tokens expire every 60 seconds
        var expiresIn = TimeUnit.SECONDS.toMillis(60);
        // Include a little buffer so that new token is fetched before the old one expires
        var expiration = Clock.systemUTC().millis() + (expiresIn - TimeUnit.SECONDS.toMillis(10));

        return token.expiringAt(expiration);
    });

    var driver = GraphDatabase.driver(dbUri, tokenManager);
}

// Some way to get a token
private String getToken() {
    return "token-string";
}
This API must not be used for switching users. Auth managers must always return tokens for the same identity. You can switch users at both query level and session level.
AuthTokenManager objects must not interact with the driver in any way, as this can cause deadlocks and undefined behavior.

Mutual TLS (client-side certificates as 2FA)

Mutual TLS (mTLS) allows you to use a client certificate as second factor for authenticating with the server. The certificate can only be used together with an authentication token and is not a replacement of regular authentication, unless authentication is disabled on the server.

The client’s certificate and public key must be placed in the server’s <NEO4J_HOME>/certificates/bolt/trusted directory. For more information on server setup, see Configure SSL over Bolt.

For mTLS to work, the driver’s connection with the server must be encrypted, i.e. the connection URI scheme must be either +s or +ssc (ex. neo4j+s://example.com:7687).

Use ClientCertificateManagers.rotating() for both static and rotating certificates.
The method takes a ClientCertificate instance.
For rotating certificates, use the .rotate() method; static certificates don’t need to be updated.

var certificateFile = new File("/path/to/cert.pem");
var privateKeyFile = new File("/path/to/key.pem");
var keyPassword = "password";  // optional
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
var certificateManager = ClientCertificateManagers.rotating(certificate);
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
    // use the driver
}
var certificateFile = new File("/path/to/cert.pem");
var privateKeyFile = new File("/path/to/key.pem");
var keyPassword = "password";  // optional
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
// instantiate the rotating certificate with an initial one
var certificateManager = ClientCertificateManagers.rotating(certificate);
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
    // use the driver...
    // ... until it's time to rotate the certificate
    var updatedCertificate = ClientCertificates.of(
        new File("/path/to/new/cert.pem")
        new File("/path/to/new/key.pem"),
        "newPassword"  // optional
    );
    certificateManager.rotate(updatedCertificate);
    // use the driver some more - new connections are opened with the new certificate
}

Logging

By default, the driver logs INFO messages through the Java logging framework java.util.logging. To change the driver’s logging behavior, use the .withLogging() method when creating a Driver object.

// import java.util.logging.Level;
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.Config;
// import org.neo4j.driver.GraphDatabase;
// import org.neo4j.driver.Logging;

try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword),
    Config.builder().withLogging(Logging.console(Level.FINE)).build())) {
    driver.verifyConnectivity();
}
Example of log output upon driver connection
2023-12-22T10:36:39.997882867 INFO org.neo4j.driver.internal.DriverFactory - Routing driver instance 1651855867 created for server address localhost:7687
2023-12-22T10:36:40.03430944 FINE io.netty.channel.DefaultChannelId - -Dio.netty.processId: 23665 (auto-detected)
2023-12-22T10:36:40.036871656 FINE io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
2023-12-22T10:36:40.037023871 FINE io.netty.util.NetUtil - -Djava.net.preferIPv6Addresses: false
2023-12-22T10:36:40.03827624 FINE io.netty.util.NetUtilInitializations - Loopback interface: lo (lo, 0:0:0:0:0:0:0:1%lo)
2023-12-22T10:36:40.038877108 FINE io.netty.util.NetUtil - /proc/sys/net/core/somaxconn: 4096
2023-12-22T10:36:40.03958947 FINE io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 04:cf:4b:ff:fe:0e:ee:99 (auto-detected)
2023-12-22T10:36:40.04531968 FINE io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
2023-12-22T10:36:40.045471749 FINE io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.targetRecords: 4
2023-12-22T10:36:40.059848221 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 40
2023-12-22T10:36:40.060000842 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 40
2023-12-22T10:36:40.060113675 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
2023-12-22T10:36:40.060219802 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 9
2023-12-22T10:36:40.060324679 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 4194304
2023-12-22T10:36:40.060442554 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
2023-12-22T10:36:40.060547232 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
2023-12-22T10:36:40.060648929 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
2023-12-22T10:36:40.060750268 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
2023-12-22T10:36:40.060858214 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimIntervalMillis: 0
2023-12-22T10:36:40.060965492 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.useCacheForAllThreads: false
2023-12-22T10:36:40.061068878 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedByteBuffersPerChunk: 1023
2023-12-22T10:36:40.069792775 FINE io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
2023-12-22T10:36:40.069957048 FINE io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 0
2023-12-22T10:36:40.070070891 FINE io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
2023-12-22T10:36:40.102235419 FINE io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkAccessible: true
2023-12-22T10:36:40.102408774 FINE io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkBounds: true
2023-12-22T10:36:40.103026138 FINE io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@1a67b908
2023-12-22T10:36:40.104721387 FINE org.neo4j.driver.internal.async.connection.ChannelConnectedListener - [0xb354eed2][localhost(127.0.0.1):7687][] C: [Bolt Handshake] [0x6060b017, 263173, 132100, 260, 3]
2023-12-22T10:36:40.106645202 FINE io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 4096
2023-12-22T10:36:40.106785483 FINE io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
2023-12-22T10:36:40.106887674 FINE io.netty.util.Recycler - -Dio.netty.recycler.chunkSize: 32
2023-12-22T10:36:40.106993748 FINE io.netty.util.Recycler - -Dio.netty.recycler.blocking: false
2023-12-22T10:36:40.107096042 FINE io.netty.util.Recycler - -Dio.netty.recycler.batchFastThreadLocalOnly: true
2023-12-22T10:36:40.11603651 FINE org.neo4j.driver.internal.async.connection.HandshakeHandler - [0xb354eed2][localhost(127.0.0.1):7687][] S: [Bolt Handshake] 5.4
2023-12-22T10:36:40.128082306 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][] C: HELLO {routing={address: "localhost:7687"}, bolt_agent={product: "neo4j-java/dev", language: "Java/17.0.9", language_details: "Optional[Eclipse Adoptium; OpenJDK 64-Bit Server VM; 17.0.9+9]", platform: "Linux; 5.15.0-91-generic; amd64"}, user_agent="neo4j-java/dev"}
2023-12-22T10:36:40.130350166 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] created. Local address: /127.0.0.1:32794, remote address: /127.0.0.1:7687
2023-12-22T10:36:40.130746872 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] acquired from the pool. Local address: /127.0.0.1:32794, remote address: /127.0.0.1:7687
2023-12-22T10:36:40.133652153 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][] C: LOGON {principal="neo4j", scheme="basic", credentials="******"}
2023-12-22T10:36:40.140017819 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][] S: SUCCESS {server="Neo4j/5.16.0", connection_id="bolt-5", hints={connection.recv_timeout_seconds: 120}}
2023-12-22T10:36:40.142229689 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {}
2023-12-22T10:36:40.14568667 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: RESET
2023-12-22T10:36:40.146897982 FINE org.neo4j.driver.internal.async.NetworkConnection - Added ConnectionReadTimeoutHandler
2023-12-22T10:36:40.14753571 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {}
2023-12-22T10:36:40.147813446 FINE org.neo4j.driver.internal.async.NetworkConnection - Removed ConnectionReadTimeoutHandler
2023-12-22T10:36:40.14895232 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] released back to the pool
2023-12-22T10:36:40.15199869 FINE org.neo4j.driver.internal.cluster.RoutingTableRegistryImpl - Routing table handler for database 'system' is added.
2023-12-22T10:36:40.152613749 FINE org.neo4j.driver.internal.cluster.RoutingTableHandlerImpl - Routing table for database 'system' is stale. Ttl 1703237800150, currentTime 1703237800152, routers [], writers [], readers [], database 'system'
2023-12-22T10:36:40.159510973 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] acquired from the pool. Local address: /127.0.0.1:32794, remote address: /127.0.0.1:7687
2023-12-22T10:36:40.165704119 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: ROUTE {address="localhost:7687"} [] system null
2023-12-22T10:36:40.168929698 FINE org.neo4j.driver.internal.async.NetworkConnection - Added ConnectionReadTimeoutHandler
2023-12-22T10:36:40.171700427 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {rt={servers: [{addresses: ["localhost:7687"], role: "WRITE"}, {addresses: ["localhost:7687"], role: "READ"}, {addresses: ["localhost:7687"], role: "ROUTE"}], ttl: 300, db: "system"}}
2023-12-22T10:36:40.17187084 FINE org.neo4j.driver.internal.async.NetworkConnection - Removed ConnectionReadTimeoutHandler
2023-12-22T10:36:40.173921853 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: RESET
2023-12-22T10:36:40.174473474 FINE org.neo4j.driver.internal.async.NetworkConnection - Added ConnectionReadTimeoutHandler
2023-12-22T10:36:40.175516332 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {}
2023-12-22T10:36:40.175679271 FINE org.neo4j.driver.internal.async.NetworkConnection - Removed ConnectionReadTimeoutHandler
2023-12-22T10:36:40.175849144 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] released back to the pool
2023-12-22T10:36:40.182085603 FINE org.neo4j.driver.internal.cluster.RoutingTableHandlerImpl - Fetched cluster composition for database 'system'. ClusterComposition{readers=[localhost:7687], writers=[localhost:7687], routers=[localhost:7687], expirationTimestamp=1703238100176, databaseName=system}
2023-12-22T10:36:40.185015699 FINE org.neo4j.driver.internal.cluster.RoutingTableHandlerImpl - Updated routing table for database 'system'. Ttl 1703238100176, currentTime 1703237800184, routers [localhost:7687], writers [localhost:7687], readers [localhost:7687], database 'system'
2023-12-22T10:36:40.18530819 INFO org.neo4j.driver.internal.InternalDriver - Closing driver instance 1651855867
2023-12-22T10:36:40.186508052 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: GOODBYE
2023-12-22T10:36:40.187291369 INFO org.neo4j.driver.internal.async.pool.ConnectionPoolImpl - Closing connection pool towards localhost(127.0.0.1):7687
2023-12-22T10:36:40.189599992 FINE org.neo4j.driver.internal.async.inbound.ChannelErrorHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] Channel is inactive
2023-12-22T10:36:40.395356347 FINE io.netty.buffer.PoolThreadCache - Freed 6 thread-local buffer(s) from thread: Neo4jDriverIO-2-2

Custom address resolver

When creating a Driver object, you can specify a resolver function to resolve the connection address the driver is initialized with. Note that addresses that the driver receives in routing tables are not resolved with the custom resolver.

You specify a resolver through the .withResolver() config method, which works with ServerAddress objects.

Connection to example.com on port 9999 is resolved to localhost on port 7687
// import java.util.Set;
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.Config;
// import org.neo4j.driver.GraphDatabase;
// import org.neo4j.driver.net.ServerAddress;

var addresses = Set.of(
    ServerAddress.of("localhost", 7687)  // omit the scheme; provide only host
);
var config = Config.builder()
    .withResolver(address -> addresses)
    .build();
try (var driver = GraphDatabase.driver("neo4j://example.com:9999", AuthTokens.basic(dbUser, dbPassword), config)) {
    driver.verifyConnectivity();
}

OCSP stapling

If OCSP stapling is enabled on the server, the driver can be configured to check for certificate revocations during SSL handshakes. OCSP stapling improves both security and performance when using CA-signed certificates.

There are two methods implementing this feature:

Both methods act on a Config.TrustStrategy object, so you have to be explicit about what certificates you want to trust and cannot rely on the driver to infer it from the connection URI scheme. This means that you have to chain these methods to Config.TrustStrategy.trustSystemCertificates(). To avoid configuration clashes, the connection URI scheme must also be set to neo4j (i.e. not neo4j+s nor neo4j+ssc).

Validate certificate stapling, but don’t fail if no stapling is found
// import org.neo4j.driver.Config;

Config config = Config.builder()
    .withEncryption()
    .withTrustStrategy(Config.TrustStrategy
        .trustSystemCertificates()
        .withVerifyIfPresentRevocationChecks())
    .build();
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), config)) {
    driver.verifyConnectivity();
}

Further connection parameters

You can find all Driver configuration parameters in the API documentation → driver.GraphDatabase.

Glossary

LTS

A Long Term Support release is one guaranteed to be supported for a number of years. Neo4j 4.4 is LTS, and Neo4j 5 will also have an LTS version.

Aura

Aura is Neo4j’s fully managed cloud service. It comes with both free and paid plans.

Cypher

Cypher is Neo4j’s graph query language that lets you retrieve data from the database. It is like SQL, but for graphs.

APOC

Awesome Procedures On Cypher (APOC) is a library of (many) functions that can not be easily expressed in Cypher itself.

Bolt

Bolt is the protocol used for interaction between Neo4j instances and drivers. It listens on port 7687 by default.

ACID

Atomicity, Consistency, Isolation, Durability (ACID) are properties guaranteeing that database transactions are processed reliably. An ACID-compliant DBMS ensures that the data in the database remains accurate and consistent despite failures.

eventual consistency

A database is eventually consistent if it provides the guarantee that all cluster members will, at some point in time, store the latest version of the data.

causal consistency

A database is causally consistent if read and write queries are seen by every member of the cluster in the same order. This is stronger than eventual consistency.

NULL

The null marker is not a type but a placeholder for absence of value. For more information, see Cypher → Working with null.

transaction

A transaction is a unit of work that is either committed in its entirety or rolled back on failure. An example is a bank transfer: it involves multiple steps, but they must all succeed or be reverted, to avoid money being subtracted from one account but not added to the other.

backpressure

Backpressure is a force opposing the flow of data. It ensures that the client is not being overwhelmed by data faster than it can handle.

transaction function

A transaction function is a callback executed by an executeRead or executeWrite call. The driver automatically re-executes the callback in case of server failure.

Driver

A Driver object holds the details required to establish connections with a Neo4j database.