Client applications

The driver object

A Neo4j client application will require a driver instance in order to provide access to the database. This driver should be made available to all parts of the application that need to interact with Neo4j. In languages where thread safety is an issue, the driver can be considered thread-safe.

A note on lifecycle

Applications will typically construct a driver instance on startup and destroy it on exit. Destroying a driver instance will immediately shut down any connections previously opened via that driver; for drivers that contain a connection pool, the entire pool will be shut down.

To construct a driver instance, a connection URI and authentication information must be supplied. Additional configuration details can be supplied if required. All of these details are immutable for the lifetime of the driver. Therefore, if multiple configurations are required (such as when working with multiple database users) then multiple driver instances must be used.

An example of driver construction and destruction can be seen below:

Example 1. The driver lifecycle
public class DriverLifecycleExample : IDisposable
{
    public IDriver Driver { get; }

    public DriverLifecycleExample(string uri, string user, string password)
    {
        Driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password));
    }

    public void Dispose()
    {
        Driver?.Dispose();
    }
}
func createDriver(uri, username, password string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""))
}

// call on application exit
func closeDriver(driver neo4j.Driver) error {
	return driver.Close()
}
public class DriverLifecycleExample implements AutoCloseable
{
    private final Driver driver;

    public DriverLifecycleExample( String uri, String user, String password )
    {
        driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ) );
    }

    @Override
    public void close() throws Exception
    {
        driver.close();
    }
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password))

driver.onCompleted = () => {
  console.log('Driver created')
}

driver.onError = error => {
  console.log(error)
}

const session = driver.session()
session.run('CREATE (i:Item)').then(() => {
  session.close()

  // ... on application exit:
  driver.close()
})
class DriverLifecycleExample:
    def __init__(self, uri, user, password):
        self._driver = GraphDatabase.driver(uri, auth=(user, password))

    def close(self):
        self._driver.close()

Connection URIs, encryption and trust

A connection URI identifies a graph database and how to connect to it. The encryption and trust settings provide detail to how that connection should be secured.

Connection URIs

The official Neo4j drivers currently support the following URI schemes and driver object types:

Table 1. Available URI schemes
URI Scheme Driver object type

bolt

Direct driver

bolt+routing

Routing driver

Direct drivers (bolt)

A direct driver is created via a bolt URI, for example: bolt://localhost:7687. This kind of driver is used to maintain connections to a single database server and is typically used when working with a single Neo4j instance or when targeting a specific member of a cluster. Note that a routing driver is generally preferable when working with a Causal Cluster.

Routing drivers (bolt+routing)

A routing driver is created via a bolt+routing URI, for example: bolt+routing://graph.example.com:7687. The address in the URI must be that of a Core Server. This kind of driver uses the Bolt Routing Protocol and works in tandem with the cluster to route transactions to available cluster members.

Routing drivers with routing context

Routing drivers with routing context are an available option when using drivers of version 1.3 or above together with a Neo4j Causal Cluster of version 3.2 or above. In such a setup, a routing driver can include a preferred routing context via the query part of the bolt+routing URI.

In the standard Neo4j configuration, routing contexts are defined on the server side by means of server policies. Thus the driver communicates the routing context to the cluster in the form of a server policy. It then obtains refined routing information back from the cluster, based on the server policy.

The address in the URI of a routing driver with routing context must be that of a Core Server.

Example 2. Configure a routing driver with routing context

This example will assume that Neo4j has been configured for server policies as described in Neo4j Operations Manual → Load balancing for multi-data center systems. In particular, a server policy called europe has been defined. Additionally, we have a server neo01.graph.example.com to which we wish to direct the driver.

This URI will use the server policy europe:

bolt+routing://neo01.graph.example.com?policy=europe

Server-side configuration to enable Routing drivers with routing context

A prerequisite for using a Routing driver with routing context is that the Neo4j database is operated on a Causal Cluster with the Multi-data center licensing option enabled. Additionally, the routing contexts must be defined within the cluster as routing policies. For details on how to configure multi-data center routing policies for a Causal Cluster, please refer to Operations Manual → Causal Clustering.

Cluster bootstrap address resolution

Drivers have the ability to intercept cluster bootstrap address resolution. This is generally performed by a routing driver on construction or after complete contact has been lost with a cluster. This hook can be useful to augment regular DNS resolution and can be used to initialize a routing driver with multiple server addresses.

The intercept hook is provided as a driver configuration option and takes the form of a callback function that accepts a single input address and yields or returns multiple output addresses. This function may hard code the output addresses or may draw them from another configuration source, as required. Output addresses can contain host names or IP addresses and are forwarded to the connection pool as initial routers.

resolution
Figure 1. Cluster bootstrap address resolution

The example below shows how to expand a single address into multiple (hard coded) output addresses:

Example 3. Custom Address Resolver
private IDriver CreateDriverWithCustomResolver(string virtualUri, IAuthToken token,
    params ServerAddress[] addresses)
{
    return GraphDatabase.Driver(virtualUri, token,
        new Config {Resolver = new ListAddressResolver(addresses), EncryptionLevel = EncryptionLevel.None});
}

public void AddPerson(string name)
{
    using (var driver = CreateDriverWithCustomResolver("bolt+routing://x.acme.com",
        AuthTokens.Basic(Username, Password),
        ServerAddress.From("a.acme.com", 7687), ServerAddress.From("b.acme.com", 7877),
        ServerAddress.From("c.acme.com", 9092)))
    {
        using (var session = driver.Session())
        {
            session.Run("CREATE (a:Person {name: $name})", new {name});
        }
    }
}

private class ListAddressResolver : IServerAddressResolver
{
    private readonly ServerAddress[] servers;

    public ListAddressResolver(params ServerAddress[] servers)
    {
        this.servers = servers;
    }

    public ISet<ServerAddress> Resolve(ServerAddress address)
    {
        return new HashSet<ServerAddress>(servers);
    }
}
func createDriverWithAddressResolver(virtualURI, username, password string, encrypted bool, addresses ...neo4j.ServerAddress) (neo4j.Driver, error) {
	// Address resolver is only valid for bolt+routing uri
	return neo4j.NewDriver(virtualURI, neo4j.BasicAuth(username, password, ""), func(config *neo4j.Config) {
		config.Encrypted = encrypted
		config.AddressResolver = func(address neo4j.ServerAddress) []neo4j.ServerAddress {
			return addresses
		}
	})
}

func addPerson(name string) error {
	const (
		username = "neo4j"
		password = "some password"
	)

	driver, err := createDriverWithAddressResolver("bolt+routing://x.acme.com", username, password, false,
		neo4j.NewServerAddress("a.acme.com", "7676"),
		neo4j.NewServerAddress("b.acme.com", "8787"),
		neo4j.NewServerAddress("c.acme.com", "9898"))
	if err != nil {
		return err
	}
	defer driver.Close()

	session, err := driver.Session(neo4j.AccessModeWrite)
	if err != nil {
		return err
	}
	defer session.Close()

	result, err := session.Run("CREATE (n:Person { name: $name})", map[string]interface{}{"name": name})
	if err != nil {
		return err
	}

	_, err = result.Consume()
	if err != nil {
		return err
	}

	return nil
}
private Driver createDriver( String virtualUri, String user, String password, ServerAddress... addresses )
{
    Config config = Config.builder()
            .withResolver( address -> new HashSet<>( Arrays.asList( addresses ) ) )
            .build();

    return GraphDatabase.driver( virtualUri, AuthTokens.basic( user, password ), config );
}

private void addPerson( String name )
{
    String username = "neo4j";
    String password = "some password";

    try ( Driver driver = createDriver( "bolt+routing://x.acme.com", username, password, ServerAddress.of( "a.acme.com", 7676 ),
            ServerAddress.of( "b.acme.com", 8787 ), ServerAddress.of( "c.acme.com", 9898 ) ) )
    {
        try ( Session session = driver.session( AccessMode.WRITE ) )
        {
            session.run( "CREATE (a:Person {name: $name})", parameters( "name", name ) );
        }
    }
}
function createDriver (virtualUri, user, password, addresses) {
  return neo4j.driver(virtualUri, neo4j.auth.basic(user, password), {
    resolver: address => addresses
  })
}

function addPerson (name) {
  const driver = createDriver('bolt+routing://x.acme.com', user, password, [
    'a.acme.com:7575',
    'b.acme.com:7676',
    'c.acme.com:8787'
  ])
  const session = driver.session(neo4j.WRITE)

  session
    .run('CREATE (n:Person { name: $name })', { name: name })
    .then(() => {
      session.close()
      driver.close()
    })
}
class CustomResolverExample:

    def __init__(self, uri, user, password):
        self._driver = GraphDatabase.driver(uri, auth=(user, password), resolver=self.resolve)

    def resolve(self, address):
        host, port = address
        if host == "x.example.com":
            yield "a.example.com", port
            yield "b.example.com", port
            yield "c.example.com", port
        else:
            yield host, port

    def close(self):
        self._driver.close()

Encryption

TLS encryption is enabled for all connections by default. This can be disabled through configuration as follows:

Example 4. Unencrypted
public IDriver CreateDriverWithCustomizedSecurityStrategy(string uri, string user, string password)
{
    return GraphDatabase.Driver(uri, AuthTokens.Basic(user, password),
        new Config {EncryptionLevel = EncryptionLevel.None});
}
func createDriverWithoutEncryption(uri, username, password string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""), func(config *neo4j.Config) {
		config.Encrypted = false
	})
}
public ConfigUnencryptedExample( String uri, String user, String password )
{
    Config config = Config.builder()
            .withoutEncryption()
            .build();

    driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
  encrypted: 'ENCRYPTION_OFF'
})
def __init__(self, uri, user, password):
    self._driver = GraphDatabase.driver(uri, auth=(user, password), encrypted=False)

The server can be modified to require encryption for all connections. Please see the Operations Manual → Configure Neo4j connectors for more information.

An attempt to connect to a server using an encryption setting not allowed by that server will result in a Service unavailable status.

Trust

During a TLS handshake, the server provides a certificate to the client application. The application can choose to accept or reject this certificate based on one of the following trust strategies:

Table 2. Trust strategies
Trust strategy Description

TRUST_ALL_CERTIFICATES (default)

Accept any certificate provided by the server, regardless of CA chain.

TRUST_CUSTOM_CA_SIGNED_CERTIFICATES

Accept any certificate that can be verified against a custom CA.

TRUST_SYSTEM_CA_SIGNED_CERTIFICATES

Accept any certificate that can be verified against the system store.

Server Name Indication (SNI) is enabled by default, allowing proxy middleware to route encrypted Bolt connections to the correct backend server.

Example 5. Trust
public IDriver CreateDriverWithCustomizedTrustStrategy(string uri, string user, string password)
{
    return GraphDatabase.Driver(uri, AuthTokens.Basic(user, password),
        new Config {TrustStrategy = TrustStrategy.TrustAllCertificates});
}
func createDriverWithTrustStrategy(uri, username, password string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""), func(config *neo4j.Config) {
		config.TrustStrategy = neo4j.TrustAny(true)
	})
}
public ConfigTrustExample( String uri, String user, String password )
{
    Config config = Config.builder()
            .withTrustStrategy( Config.TrustStrategy.trustAllCertificates() )
            .build();

    driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
  encrypted: 'ENCRYPTION_ON',
  trust: 'TRUST_ALL_CERTIFICATES'
})
def __init__(self, uri, user, password):
    self._driver = GraphDatabase.driver(uri, auth=(user, password), trust=TRUST_ALL_CERTIFICATES)

Examples

The table below provides example code snippets for different deployment configurations. Each snippet expects an auth variable to have been previously defined, containing the authentication details for that connection.

Example 6. Connecting to a service

The table below illustrates examples of how to connect to a service with routing:

Product Security Code snippet Comments

Neo4j Aura

Secured with full certificate

String uri = "bolt+routing://graph.example.com:7687";
IDriver driver = GraphDatabase.Driver(uri, auth,
           new Config {TrustStrategy = TrustStrategy.TrustSystemCaSignedCertificates});

This is the default (and only option) for Neo4j Aura

Neo4j 4.x

Unsecured

String uri = "bolt+routing://graph.example.com:7687";
IDriver driver = GraphDatabase.Driver(uri, auth,
                     new Config {EncryptionLevel = EncryptionLevel.None});

This is the default for Neo4j 4.x series

Neo4j 4.x

Secured with full certificate

String uri = "bolt+routing://graph.example.com:7687";
IDriver driver = GraphDatabase.Driver(uri, auth,
           new Config {TrustStrategy = TrustStrategy.TrustSystemCaSignedCertificates});

Neo4j 4.x

Secured with self-signed certificate

GraphDatabase.Driver("bolt+routing://graph.example.com:7687", auth)

Neo4j 3.x

Secured with full certificate

String uri = "bolt+routing://graph.example.com:7687";
IDriver driver = GraphDatabase.Driver(uri, auth,
           new Config {TrustStrategy = TrustStrategy.TrustSystemCaSignedCertificates});

Neo4j 3.x

Secured with self-signed certificate

GraphDatabase.Driver("bolt+routing://graph.example.com:7687", auth)

This is the default for Neo4j 3.x series

Neo4j 3.x

Unsecured

String uri = "bolt+routing://graph.example.com:7687";
IDriver driver = GraphDatabase.Driver(uri, auth,
                     new Config {EncryptionLevel = EncryptionLevel.None});
To connect to a service without routing, you can replace bolt+routing with bolt.

The table below illustrates examples of how to connect to a service with routing.

Product Security Code snippet Comments

Neo4j Aura

Secured with full certificate

uri := "bolt+routing://graph.example.com:7687"

driver, err := neo4j.NewDriver(uri, auth, func(config *neo4j.Config) {
        config.TrustStrategy = neo4j.TrustSystem(true)
})

This is the default (and only option) for Neo4j Aura

Neo4j 4.x

Unsecured

uri := "bolt+routing://graph.example.com:7687"

driver, err := neo4j.NewDriver(uri, auth, func(config *neo4j.Config) {
        config.Encrypted = false
})

This is the default for Neo4j 4.x series

Neo4j 4.x

Secured with full certificate

uri := "bolt+routing://graph.example.com:7687"

driver, err := neo4j.NewDriver(uri, auth, func(config *neo4j.Config) {
        config.TrustStrategy = neo4j.TrustSystem(true)
})

Neo4j 4.x

Secured with self-signed certificate

driver, err := neo4j.NewDriver("bolt+routing://graph.example.com:7687", auth)

Neo4j 3.x

Secured with full certificate

uri := "bolt+routing://graph.example.com:7687"

driver, err := neo4j.NewDriver(uri, auth, func(config *neo4j.Config) {
        config.TrustStrategy = neo4j.TrustSystem(true)
})

Neo4j 3.x

Secured with self-signed certificate

driver, err := neo4j.NewDriver("bolt+routing://graph.example.com:7687", auth)

This is the default for Neo4j 3.x series

Neo4j 3.x

Unsecured

uri := "bolt+routing://graph.example.com:7687"

driver, err := neo4j.NewDriver(uri, auth, func(config *neo4j.Config) {
        config.Encrypted = false
})
To connect to a service without routing, you can replace bolt+routing with bolt.

The table below illustrates examples of how to connect to a service with routing.

Product Security Code snippet Comments

Neo4j Aura

Secured with full certificate

String uri = "bolt+routing://graph.example.com:7687";
Config config = Config.build()
                      .withTrustStrategy( trustSystemCertificates() )
                      .build();

This is the default (and only option) for Neo4j Aura

Neo4j 4.x

Unsecured

String uri = "bolt+routing://graph.example.com:7687";
Config config = Config.build()
                      .withoutEncryption()
                      .build();

GraphDatabase.driver( uri, auth, config );

This is the default for Neo4j 4.x series

Neo4j 4.x

Secured with full certificate

String uri = "bolt+routing://graph.example.com:7687";
Config config = Config.build()
                      .withTrustStrategy( trustSystemCertificates() )
                      .build();

Neo4j 4.x

Secured with self-signed certificate

GraphDatabase.driver("bolt+routing://graph.example.com:7687", auth)

Neo4j 3.x

Secured with full certificate

String uri = "bolt+routing://graph.example.com:7687";
Config config = Config.build()
                      .withTrustStrategy( trustSystemCertificates() )
                      .build();

Neo4j 3.x

Secured with self-signed certificate

GraphDatabase.driver("bolt+routing://graph.example.com:7687", auth)

This is the default for Neo4j 3.x series

Neo4j 3.x

Unsecured

String uri = "bolt+routing://graph.example.com:7687";
Config config = Config.build()
                      .withoutEncryption()
                      .build();

GraphDatabase.driver( uri, auth, config );
To connect to a service without routing, you can replace bolt+routing with bolt.

The table below illustrates examples of how to connect to a service with routing.

Product Security Code snippet Comments

Neo4j Aura

Secured with full certificate

const uri = 'bolt+routing://graph.example.com:7687'
const driver = neo4j.driver(uri,auth, {
    trust: 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
})

This is the default (and only option) for Neo4j Aura

Neo4j 4.x

Unsecured

const uri = 'bolt+routing://graph.example.com:7687'
const driver = neo4j.driver(uri, auth, {
  encrypted: 'ENCRYPTION_OFF'
})

This is the default for Neo4j 4.x series

Neo4j 4.x

Secured with full certificate

const uri = 'bolt+routing://graph.example.com:7687'
const driver = neo4j.driver(uri,auth, {
    trust: 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
})

Neo4j 4.x

Secured with self-signed certificate

neo4j.driver("bolt+routing://graph.example.com:7687", auth)

Neo4j 3.x

Secured with full certificate

const uri = 'bolt+routing://graph.example.com:7687'
const driver = neo4j.driver(uri,auth, {
    trust: 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'
})

Neo4j 3.x

Secured with self-signed certificate

neo4j.driver("bolt+routing://graph.example.com:7687", auth)

This is the default for Neo4j 3.x series

Neo4j 3.x

Unsecured

const uri = 'bolt+routing://graph.example.com:7687'
const driver = neo4j.driver(uri, auth, {
  encrypted: 'ENCRYPTION_OFF'
})
To connect to a service without routing, you can replace bolt+routing with bolt.

The table below illustrates examples of how to connect to a service with routing.

Product Security Code snippet Comments

Neo4j Aura

Secured with full certificate

uri = "bolt+routing://graph.example.com:7687"
GraphDatabase.driver(uri, auth, trust=TRUST_SYSTEM_CA_SIGNED_CERTIFICATES)

This is the default (and only option) for Neo4j Aura

Neo4j 4.x

Unsecured

uri = "bolt+routing://graph.example.com:7687"
GraphDatabase.driver(uri, auth, encrypted=False)

This is the default for Neo4j 4.x series

Neo4j 4.x

Secured with full certificate

uri = "bolt+routing://graph.example.com:7687"
GraphDatabase.driver(uri, auth, trust=TRUST_SYSTEM_CA_SIGNED_CERTIFICATES)

Neo4j 4.x

Secured with self-signed certificate

GraphDatabase.driver("bolt+routing://graph.example.com:7687", auth)

Neo4j 3.x

Secured with full certificate

uri = "bolt+routing://graph.example.com:7687"
GraphDatabase.driver(uri, auth, trust=TRUST_SYSTEM_CA_SIGNED_CERTIFICATES)

Neo4j 3.x

Secured with self-signed certificate

GraphDatabase.driver("bolt+routing://graph.example.com:7687", auth)

This is the default for Neo4j 3.x series

Neo4j 3.x

Unsecured

uri = "bolt+routing://graph.example.com:7687"
GraphDatabase.driver(uri, auth, encrypted=False)
To connect to a service without routing, you can replace bolt+routing with bolt.

Authentication

Authentication details are provided as an auth token which contains the user names, passwords or other credentials required to access the database. Neo4j supports multiple authentication standards but uses basic authentication by default.

Basic authentication

The basic authentication scheme is backed by a password file stored within the server and requires applications to provide a user name and password. For this, use the basic auth helper:

Example 7. Basic authentication
public IDriver CreateDriverWithBasicAuth(string uri, string user, string password)
{
    return GraphDatabase.Driver(uri, AuthTokens.Basic(user, password));
}
func createDriverWithBasicAuth(uri, username, password string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""))
}
public BasicAuthExample( String uri, String user, String password )
{
    driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ) );
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password))
def __init__(self, uri, user, password):
    self._driver = GraphDatabase.driver(uri, auth=(user, password))

The basic authentication scheme can also be used to authenticate against an LDAP server.

Kerberos authentication

The Kerberos authentication scheme provides a simple way to create a Kerberos authentication token with a base64 encoded server authentication ticket. The best way to create a Kerberos authentication token is shown below:

Example 8. Kerberos authentication
public IDriver CreateDriverWithKerberosAuth(string uri, string ticket)
{
    return GraphDatabase.Driver(uri, AuthTokens.Kerberos(ticket),
        new Config {EncryptionLevel = EncryptionLevel.None});
}
func createDriverWithKerberosAuth(uri, ticket string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.KerberosAuth(ticket))
}
public KerberosAuthExample( String uri, String ticket )
{
    driver = GraphDatabase.driver( uri, AuthTokens.kerberos( ticket ) );
}
const driver = neo4j.driver(uri, neo4j.auth.kerberos(ticket))
def __init__(self, uri, ticket):
    self._driver = GraphDatabase.driver(uri, auth=kerberos_auth(ticket))

The Kerberos authentication token can only be understood by the server if the server has the Kerberos Add-on installed.

Custom authentication

For advanced deployments, where a custom security provider has been built, the custom authentication helper can be used.

Example 9. Custom authentication
public IDriver CreateDriverWithCustomizedAuth(string uri,
    string principal, string credentials, string realm, string scheme,
    Dictionary<string, object> parameters)
{
    return GraphDatabase.Driver(uri, AuthTokens.Custom(principal, credentials, realm, scheme, parameters),
        new Config {EncryptionLevel = EncryptionLevel.None});
}
func createDriverWithCustomAuth(uri, principal, credentials, realm, scheme string, parameters map[string]interface{}) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.CustomAuth(scheme, principal, credentials, realm, parameters))
}
public CustomAuthExample( String uri, String principal, String credentials, String realm, String scheme,
        Map<String,Object> parameters )
{
    driver = GraphDatabase.driver( uri, AuthTokens.custom( principal, credentials, realm, scheme, parameters ) );
}
const driver = neo4j.driver(
  uri,
  neo4j.auth.custom(principal, credentials, realm, scheme, parameters)
)
def __init__(self, uri, principal, credentials, realm, scheme, **parameters):
    self._driver = GraphDatabase.driver(uri, auth=custom_auth(principal, credentials, realm, scheme, **parameters))

Configuration

Connection pool management

The driver maintains a pool of connections. The pooled connections are reused by sessions and transactions to avoid the overhead added by establishing new connections for every query. The connection pool always starts up empty. New connections are created on demand by sessions and transactions. When a session or a transaction is done with its execution, the connection will be returned to the pool to be reused.

Application users can tune connection pool settings to configure the driver for different use cases based on client performance requirements and database resource consumption limits.

Detailed descriptions of connection pool settings available via driver configuration are listed below:

MaxConnectionLifetime

Pooled connections older than this threshold will be closed and removed from the pool. The actual removal happens during connection acquisition so that the new session returned is never backed by an old connection. Setting this option to a low value will cause a high connection churn, and can result in a performance drop. It is recommended to pick a value smaller than the maximum lifetime exposed by the surrounding system infrastructure (such as operating system, router, load balancer, proxy and firewall). Negative values result in lifetime not being checked.

Default value: 1h.

MaxConnectionPoolSize

This setting defines the maximum total number of connections allowed, per host, to be managed by the connection pool. In other words, for a direct driver, this sets the maximum number of connections towards a single database server. For a routing driver this sets the maximum amount of connections per cluster member. If a session or transaction tries to acquire a connection at a time when the pool size is at its full capacity, it must wait until a free connection is available in the pool or the request to acquire a new connection times out. The connection acquiring timeout is configured via ConnectionAcquisitionTimeout.

Default value: This is different for different drivers, but is a number in the order of 100.

ConnectionAcquisitionTimeout

This setting limits the amount of time a session or transaction can spend waiting for a free connection to appear in the pool before throwing an exception. The exception thrown in this case is ClientException. Timeout only applies when connection pool is at its max capacity.

Default value: 1m.

Example 10. Connection pool management
public IDriver CreateDriverWithCustomizedConnectionPool(string uri, string user, string password)
{
    return GraphDatabase.Driver(uri, AuthTokens.Basic(user, password),
        new Config
        {
            MaxConnectionLifetime = TimeSpan.FromMinutes(30),
            MaxConnectionPoolSize = 50,
            ConnectionAcquisitionTimeout = TimeSpan.FromMinutes(2)
        });
}
func createDriverWithCustomizedConnectionPool(uri, username, password string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""), func(config *neo4j.Config) {
		config.MaxConnectionLifetime = 30 * time.Minute
		config.MaxConnectionPoolSize = 50
		config.ConnectionAcquisitionTimeout = 2 * time.Minute
	})
}
public ConfigConnectionPoolExample( String uri, String user, String password )
{
    Config config = Config.builder()
            .withMaxConnectionLifetime( 30, TimeUnit.MINUTES )
            .withMaxConnectionPoolSize( 50 )
            .withConnectionAcquisitionTimeout( 2, TimeUnit.MINUTES )
            .build();

    driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
  maxConnectionLifetime: 3 * 60 * 60 * 1000, // 3 hours
  maxConnectionPoolSize: 50,
  connectionAcquisitionTimeout: 2 * 60 * 1000 // 120 seconds
})
def __init__(self, uri, user, password):
    self._driver = GraphDatabase.driver(uri, auth=(user, password),
                                        max_connection_lifetime=30 * 60, max_connection_pool_size=50,
                                        connection_acquisition_timeout=2 * 60)

Connection timeout

To configure the maximum time allowed to establish a connection, pass a duration value to the driver configuration. For example:

Example 11. Connection timeout
public IDriver CreateDriverWithCustomizedConnectionTimeout(string uri, string user, string password)
{
    return GraphDatabase.Driver(uri, AuthTokens.Basic(user, password),
        new Config {ConnectionTimeout = TimeSpan.FromSeconds(15)});
}
func createDriverWithConnectionTimeout(uri, username, password string) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""), func(config *neo4j.Config) {
		config.SocketConnectTimeout = 15 * time.Second
	})
}
public ConfigConnectionTimeoutExample( String uri, String user, String password )
{
    Config config = Config.builder()
            .withConnectionTimeout( 15, SECONDS )
            .build();

    driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
  connectionTimeout: 20 * 1000 // 20 seconds
})
def __init__(self, uri, user, password):
    self._driver = GraphDatabase.driver(uri, auth=(user, password), connection_timeout=15)

Max retry time

To configure retry behavior, supply a value for the maximum time in which to keep attempting retries of transaction functions. For example:

Example 12. Max retry time
public IDriver CreateDriverWithCustomizedMaxRetryTime(string uri, string user, string password)
{
    return GraphDatabase.Driver(uri, AuthTokens.Basic(user, password),
        new Config {MaxTransactionRetryTime = TimeSpan.FromSeconds(15)});
}
// This driver is used to run queries, needs actual TLS configuration as well.
func createDriverWithMaxRetryTime(uri, username, password string, encrypted bool) (neo4j.Driver, error) {
	return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, ""), func(config *neo4j.Config) {
		config.MaxTransactionRetryTime = 15 * time.Second
		config.Encrypted = encrypted
	})
}
public ConfigMaxRetryTimeExample( String uri, String user, String password )
{
    Config config = Config.builder()
            .withMaxTransactionRetryTime( 15, SECONDS )
            .build();

    driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );
}
const maxRetryTimeMs = 15 * 1000 // 15 seconds
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
  maxTransactionRetryTime: maxRetryTimeMs
})
def __init__(self, uri, user, password):
    self._driver = GraphDatabase.driver(uri, auth=(user, password), max_retry_time=15)

Note that the time specified here does not take into account the running time of the unit of work itself, merely a limit after which retries will no longer be attempted.

Service unavailable

A Service unavailable status will be signalled when the driver is no longer able to establish communication with the server, even after retries. Encountering this condition usually indicates a fundamental networking or database problem. Applications should be designed to cater for this eventuality.

Example 13. Service unavailable
public bool AddItem()
{
    try
    {
        using (var session = Driver.Session())
        {
            return session.WriteTransaction(
                tx =>
                {
                    tx.Run("CREATE (a:Item)");
                    return true;
                }
            );
        }
    }
    catch (ServiceUnavailableException)
    {
        return false;
    }
}
func createItem(driver neo4j.Driver) error {
	session, err := driver.Session(neo4j.AccessModeWrite)
	if err != nil {
		return err
	}
	defer session.Close()

	_, err = session.WriteTransaction(func(tx neo4j.Transaction) (interface{}, error) {
		result, err := tx.Run("CREATE (a:Item)", nil)
		if err != nil {
			return nil, err
		}

		return result.Consume()
	})

	return err
}

func addItem(driver neo4j.Driver) bool {
	if err := createItem(driver); err != nil {
		if neo4j.IsServiceUnavailable(err) {
			// perform some action
		}

		return false
	}

	return true
}
public boolean addItem()
{
    try ( Session session = driver.session() )
    {
        return session.writeTransaction( new TransactionWork<Boolean>()
        {
            @Override
            public Boolean execute( Transaction tx )
            {
                tx.run( "CREATE (a:Item)" );
                return true;
            }
        } );
    }
    catch ( ServiceUnavailableException ex )
    {
        return false;
    }
}
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
  maxTransactionRetryTime: 3000
})
const session = driver.session()

const writeTxPromise = session.writeTransaction(tx =>
  tx.run('CREATE (a:Item)')
)

writeTxPromise.catch(error => {
  if (error.code === neo4j.error.SERVICE_UNAVAILABLE) {
    console.log('Unable to create node: ' + error.code)
  }
})
def add_item(self):
    try:
        with self._driver.session() as session:
            session.write_transaction(lambda tx: tx.run("CREATE (a:Item)"))
        return True
    except ServiceUnavailable:
        return False