Configure Tomcat 11 database connection pooling with JNDI and HikariCP for high availability

Intermediate 25 min Apr 17, 2026 11 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up production-grade database connection pooling in Tomcat 11 using JNDI resources and HikariCP for optimal performance and high availability. Learn to configure server.xml, context.xml, and monitor connection pools effectively.

Prerequisites

  • Root or sudo access
  • Basic knowledge of Java web applications
  • Database server (PostgreSQL or MySQL) running

What this solves

Database connection pooling prevents your Tomcat applications from creating expensive database connections for every request. This tutorial shows you how to configure Tomcat 11 with JNDI resources and HikariCP connection pooling for production workloads that require high availability and optimal database performance.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions of all dependencies.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install Java 21 and Tomcat 11

Tomcat 11 requires Java 11 or higher. We'll install OpenJDK 21 for optimal performance and compatibility.

sudo apt install -y openjdk-21-jdk wget
sudo dnf install -y java-21-openjdk-devel wget

Download and install Tomcat 11

Download the latest Tomcat 11 release and install it to a dedicated directory with proper ownership.

cd /opt
sudo wget https://archive.apache.org/dist/tomcat/tomcat-11/v11.0.0/bin/apache-tomcat-11.0.0.tar.gz
sudo tar xzf apache-tomcat-11.0.0.tar.gz
sudo mv apache-tomcat-11.0.0 tomcat11
sudo useradd -r -s /bin/false tomcat
sudo chown -R tomcat:tomcat /opt/tomcat11

Install database drivers

Download the JDBC drivers for your database and place them in Tomcat's lib directory. This example uses PostgreSQL and MySQL drivers.

cd /opt/tomcat11/lib
sudo wget https://jdbc.postgresql.org/download/postgresql-42.7.1.jar
sudo wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-8.2.0.jar
sudo chown tomcat:tomcat *.jar

Download HikariCP connection pool library

HikariCP provides superior performance compared to Tomcat's default DBCP. Download the latest version to Tomcat's lib directory.

cd /opt/tomcat11/lib
sudo wget https://repo1.maven.org/maven2/com/zaxxer/HikariCP/5.1.0/HikariCP-5.1.0.jar
sudo chown tomcat:tomcat HikariCP-5.1.0.jar

Configure JNDI database resources in server.xml

Add database connection pool configurations to Tomcat's server.xml file. This creates global JNDI resources available to all applications.

<GlobalNamingResources>
  <!-- PostgreSQL Connection Pool -->
  <Resource name="jdbc/PostgresDB"
            auth="Container"
            type="javax.sql.DataSource"
            factory="com.zaxxer.hikari.HikariJNDIFactory"
            jdbcUrl="jdbc:postgresql://localhost:5432/myapp"
            username="dbuser"
            password="securepassword123"
            driverClassName="org.postgresql.Driver"
            maximumPoolSize="20"
            minimumIdle="5"
            connectionTimeout="30000"
            idleTimeout="600000"
            maxLifetime="1800000"
            leakDetectionThreshold="60000" />
            
  <!-- MySQL Connection Pool -->
  <Resource name="jdbc/MySQLDB"
            auth="Container"
            type="javax.sql.DataSource"
            factory="com.zaxxer.hikari.HikariJNDIFactory"
            jdbcUrl="jdbc:mysql://localhost:3306/myapp"
            username="dbuser"
            password="securepassword123"
            driverClassName="com.mysql.cj.jdbc.Driver"
            maximumPoolSize="25"
            minimumIdle="5"
            connectionTimeout="30000"
            idleTimeout="600000"
            maxLifetime="1800000"
            leakDetectionThreshold="60000"
            cachePrepStmts="true"
            prepStmtCacheSize="250"
            prepStmtCacheSqlLimit="2048" />
</GlobalNamingResources>

Configure resource links in context.xml

Create resource links in the global context.xml to make JNDI resources available to web applications.

<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
    
    <!-- Link to global JNDI resources -->
    <ResourceLink name="jdbc/PostgresDB"
                  global="jdbc/PostgresDB"
                  type="javax.sql.DataSource" />
                  
    <ResourceLink name="jdbc/MySQLDB"
                  global="jdbc/MySQLDB"
                  type="javax.sql.DataSource" />
</Context>

Optimize HikariCP configuration for high availability

Update the server.xml with production-optimized HikariCP settings for better performance and reliability.

<!-- Production-optimized PostgreSQL Pool -->
<Resource name="jdbc/PostgresDB"
          auth="Container"
          type="javax.sql.DataSource"
          factory="com.zaxxer.hikari.HikariJNDIFactory"
          jdbcUrl="jdbc:postgresql://localhost:5432/myapp?prepareThreshold=0&amp;preparedStatementCacheQueries=256&amp;preparedStatementCacheSizeMiB=5"
          username="dbuser"
          password="securepassword123"
          driverClassName="org.postgresql.Driver"
          maximumPoolSize="30"
          minimumIdle="10"
          connectionTimeout="20000"
          idleTimeout="300000"
          maxLifetime="1200000"
          leakDetectionThreshold="30000"
          validationTimeout="5000"
          connectionTestQuery="SELECT 1"
          initializationFailTimeout="1"
          isolateInternalQueries="true"
          allowPoolSuspension="true"
          readOnly="false"
          registerMbeans="true" />

Create systemd service for Tomcat

Create a systemd service file to manage Tomcat as a system service with proper Java memory settings.

[Unit]
Description=Apache Tomcat 11 Web Application Container
After=network.target

[Service]
Type=forking

Environment=JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
Environment=CATALINA_PID=/opt/tomcat11/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat11
Environment=CATALINA_BASE=/opt/tomcat11
Environment='CATALINA_OPTS=-Xms1024M -Xmx2048M -server -XX:+UseG1GC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Dcom.zaxxer.hikari.housekeeping.periodMs=30000'

ExecStart=/opt/tomcat11/bin/startup.sh
ExecStop=/opt/tomcat11/bin/shutdown.sh

User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

Configure connection pool monitoring

Enable JMX monitoring for HikariCP by adding JMX configuration to the Tomcat service.

sudo mkdir -p /opt/tomcat11/conf/Catalina/localhost
sudo tee /opt/tomcat11/conf/Catalina/localhost/manager.xml > /dev/null <<EOF
<Context privileged="true" antiResourceLocking="false" 
         docBase="\${catalina.home}/webapps/manager">
  <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
                   sameSiteCookies="strict" />
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.0\.0\.1|::1|0:0:0:0:0:0:0:1" />
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$[12])?|java\.util\.(?:Linked)?HashMap"/>
</Context>
EOF
sudo chown tomcat:tomcat /opt/tomcat11/conf/Catalina/localhost/manager.xml

Configure web.xml for connection pool usage

Update your application's web.xml to reference the JNDI database resources.

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
  version="6.0">

  <resource-ref>
    <description>PostgreSQL Database Connection</description>
    <res-ref-name>jdbc/PostgresDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
  
  <resource-ref>
    <description>MySQL Database Connection</description>
    <res-ref-name>jdbc/MySQLDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

</web-app>

Enable and start Tomcat service

Reload systemd configuration and start the Tomcat service with connection pooling enabled.

sudo systemctl daemon-reload
sudo systemctl enable tomcat
sudo systemctl start tomcat
sudo systemctl status tomcat

Verify your setup

Check that Tomcat is running correctly and the connection pools are properly configured.

sudo systemctl status tomcat
sudo ss -tlnp | grep 8080
sudo tail -f /opt/tomcat11/logs/catalina.out

Test JNDI resource availability by checking the logs for HikariCP initialization messages:

sudo grep -i hikari /opt/tomcat11/logs/catalina.out
curl -I http://localhost:8080

Monitor connection pool statistics through JMX or application logs:

sudo netstat -an | grep 5432
sudo netstat -an | grep 3306

Configure connection pool monitoring

Enable JMX monitoring

Add JMX configuration to monitor HikariCP pools in production environments.

Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Dcom.zaxxer.hikari.housekeeping.periodMs=30000 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false'

Create connection pool health check

Implement a simple Java servlet to monitor connection pool health and availability.

<%@ page import="javax.naming., javax.sql., java.sql.*" %>
<%
response.setContentType("application/json");
try {
    InitialContext ctx = new InitialContext();
    DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/PostgresDB");
    Connection conn = ds.getConnection();
    
    if (conn != null && !conn.isClosed()) {
        conn.close();
        out.println("{\"status\":\"healthy\",\"database\":\"connected\"}");
    } else {
        response.setStatus(503);
        out.println("{\"status\":\"unhealthy\",\"database\":\"disconnected\"}");
    }
} catch (Exception e) {
    response.setStatus(503);
    out.println("{\"status\":\"error\",\"message\":\"" + e.getMessage() + "\"}");
}
%>

Common issues

SymptomCauseFix
ClassNotFoundException for HikariCPHikariCP JAR not in lib directoryEnsure HikariCP JAR is in /opt/tomcat11/lib/
Connection timeout errorsDatabase server unreachableCheck database server status and network connectivity
Pool exhausted exceptionsmaximumPoolSize too smallIncrease maximumPoolSize in server.xml based on load
Memory leaks on restartConnections not properly closedEnable leakDetectionThreshold and fix application code
Authentication failuresIncorrect database credentialsVerify username/password in JNDI resource configuration
JNDI lookup failuresResource links not configuredEnsure ResourceLink entries in context.xml match server.xml names
Warning: Never store database passwords in plain text in production. Use environment variables or external configuration management tools for sensitive credentials.

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.