Super Java Host
  1. Home
  2. Guides
  3. Tomcat with PostgreSQL or MySQL

Connect Tomcat to PostgreSQL or MySQL

Install the database, create a dedicated user, drop the JDBC driver into Tomcat and define a pooled DataSource your application looks up by name.

1. Install the database

Choose one.

# PostgreSQL
sudo apt install -y postgresql
sudo -u postgres psql -c "CREATE USER appuser WITH PASSWORD 'change-me';"
sudo -u postgres psql -c "CREATE DATABASE appdb OWNER appuser;"

# MariaDB (MySQL-compatible)
sudo apt install -y mariadb-server
sudo mysql -e "CREATE DATABASE appdb CHARACTER SET utf8mb4;"
sudo mysql -e "CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'change-me';"
sudo mysql -e "GRANT ALL ON appdb.* TO 'appuser'@'localhost'; FLUSH PRIVILEGES;"

Generate a real password with openssl rand -hex 16. Both packages listen on localhost by default. Confirm with sudo ss -ltnp | grep -E '5432|3306': the address must be 127.0.0.1. Never open a database port to the internet.

2. Add the JDBC driver to Tomcat

Download the driver jar for your database from Maven Central into Tomcat's shared lib folder. Look up the current version number first.

cd /opt/tomcat/lib
# PostgreSQL
sudo curl -fSLO https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.4/postgresql-42.7.4.jar
# MariaDB
sudo curl -fSLO https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/3.5.1/mariadb-java-client-3.5.1.jar
sudo chown tomcat:tomcat *.jar

A driver in lib is required for a JNDI DataSource defined by Tomcat. If your application bundles its own pool and driver in WEB-INF/lib, skip this and configure the pool inside the application.

3. Define the DataSource

For one application, put it in META-INF/context.xml inside the WAR, or in /opt/tomcat/conf/Catalina/localhost/ROOT.xml on the server, which keeps the password out of the WAR:

<Context>
  <Resource name="jdbc/appdb" auth="Container" type="javax.sql.DataSource"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="org.postgresql.Driver"
            url="jdbc:postgresql://127.0.0.1:5432/appdb"
            username="appuser" password="change-me"
            maxActive="20" maxIdle="5" minIdle="2" initialSize="2"
            maxWait="10000"
            testOnBorrow="true" validationQuery="SELECT 1"
            removeAbandoned="true" removeAbandonedTimeout="120" />
</Context>

For MariaDB use org.mariadb.jdbc.Driver and jdbc:mariadb://127.0.0.1:3306/appdb. Protect the file: sudo chmod 640 ROOT.xml; sudo chown tomcat:tomcat ROOT.xml.

4. Look it up from the application

Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/appdb");
try (Connection c = ds.getConnection()) {
    // use the connection
}

With Spring, point spring.datasource.jndi-name to java:comp/env/jdbc/appdb. Always close connections: unclosed ones are the usual reason for the pool running dry. removeAbandoned above is a safety net, not a fix.

5. Restart and test

sudo systemctl restart tomcat
sudo tail -n 50 /opt/tomcat/logs/catalina.out

Sizing on a small server

  • Every connection costs memory in the database too. A pool of 10 to 20 is plenty for most applications on a 4 GB server. A large pool does not make queries faster.
  • With a database on the same machine, leave about 15% of RAM to it for buffers. See how much RAM a Java app needs.
  • Take a daily dump and copy it off the server: backup guide.

Plans with a database on the server are described on Java hosting with a database.

Last updated October 29, 2026.

Your own Java server, billed monthly

Plans from €15.30 a month. Set up for you, or run for you.