# c3p0: a JDBC connection pool with a statement cache

> c3p0 is MChange's mature JDBC connection pool for Java, with a prepared statement cache, a set of built-in DataSource implementations and a long history of concurrency tuning. It suits a legacy Java application that needs a pool it can configure without a framework, and the deserialization gadget history in the README is something to read before you deploy it.

**swaldman/c3p0** — a mature, highly concurrent JDBC Connection pooling library, with support for caching and reuse of PreparedStatements.

- Repository: https://github.com/swaldman/c3p0
- Website: http://www.mchange.com/projects/c3p0
- Stars: 1,319 · Forks: 345
- Language: Java
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/swaldman-c3p0

## What the library is, and where it comes from

c3p0 is a mature, highly concurrent JDBC Connection pooling library, with support for caching and reuse of PreparedStatement objects. It is available as a managed dependency on Maven Central under the group id com.mchange and the artifact id c3p0, and the project homepage is mchange.com/projects/c3p0. The primary language is Java, the default branch is `0.15.x`, and the last push was on 2026-10-13. The repository has no GitHub releases, which is consistent with a library that is published to Maven Central rather than tracked as a set of tags here, and the release notes are in the tree instead, with `RELEASE_NOTES-c3p0-0.14.0`, `RELEASE_NOTES-c3p0-0.14.1`, `RELEASE_NOTES-c3p0-0.15.0` and a `release-notes-past/` directory. The version history matters here for a specific reason discussed below.

## The deserialization gadget warning, which is the first thing in the README

The README opens with a warning that deserves attention before the feature list. c3p0 and its dependencies have been used as deserialization gadgets, with a link to an article on what a gadget chain actually is, and the documentation carries a security note. The vulnerabilities that enable this are addressed as of c3p0-0.12.0. The version history then explains the hardening in stages. c3p0-0.13.0 eliminates from c3p0's classpath the `javax.naming.Reference` to Java serialization pipeline that makes the mischief possible. c3p0-0.14.0 further hardens JNDI and serialization-related utilities, and prevents attacks that rely on JavaBeans-related libraries triggering `getConnection()` or `getPooledConnection()` on maliciously constructed DataSource instances. The README closes that section with please update your applications. The practical reading is that a c3p0 version below 0.12.0 on a classpath reachable by untrusted deserialization is a liability, and the mitigation is a version bump rather than configuration.

## Building it, and the mill launcher

For now, at v0.15.0, c3p0 is built under a Java 11 VM, targeting JDK 7 classfiles for continued compatibility with legacy apps. The build relies on the mill build tool, and the README is specific about how to invoke it. You do not need to install it, because the launcher in this repository fetches the version the build pins, and a mill on your PATH may be too old to parse `build.mill`. Within the repository directory, you run:

```plaintext
$ ./mill jar
```

and the raw library lands in `out/jar.dest/out.jar`. Publishing to a local ivy repository is `./mill publishLocal` after customising `publishVersion` in `build.mill`, and the documentation is built with `./mill doc.docroot` into `out/doc/docroot.dest/index.html`. The presence of a checked-in launcher and a pinned build version is the pattern of a project that has had a broken build tool before and decided to make the toolchain part of the repository.

## The generated-source model, and the freshness check

Much of c3p0 is generated during the build, which explains the unusual set of directories in the tree. There is a `Debug` class per package beneath `src`, JavaBean base classes generated from the `beangen-xml` files, explicit `BeanInfo`s reflected off those compiled beans, and the JDBC proxies. The `bean/`, `beanInfo/`, `proxy/` and `src-proxy-interface/` directories are the generated output. The consequence the README draws is that you should never need `./mill clean` to get a correct jar out of that, and then it provides a tool to prove the claim. `./checkBuildFreshness` perturbs a build input of each kind, a new package under `src`, a new property in a `beangen-xml`, a change to generator code, and checks that an incremental build afterwards matches a clean build of the same sources, that the perturbation really did move the output, and that reverting restores the artifacts bit for bit. It takes well under a minute, exits nonzero on failure, and leaves your working tree as it found it. That is a stronger guarantee than most libraries make about their generators.

## Reproducible builds, and the SOURCE_DATE_EPOCH trick

c3p0 supports reproducible builds of its binary and source jar files, though it does not yet support reproducible builds of doc jars. To prevent everchanging timestamps, the recommendation is to set the SOURCE_DATE_EPOCH environment variable when building. The build reads it from the environment of the mill command you invoke and treats it as a build input, so changing it is itself a reason to regenerate, and neither the `-i` flag nor a clean build is required:

```plaintext
$ export SOURCE_DATE_EPOCH=1234567890
$ ./mill jar
$ ./mill sourceJar
```

The two files, `out/jar.dest/out.jar` and `out/sourceJar.dest/out.jar`, will then have been deterministically and reproducibly built. For a library that has been in production for a very long time and is now shipped in many distributions, that matters, because a reproducible artifact is one an organisation can verify and vendor without re-deriving the build.

## The test suite, and the honest description of it

The testing section is candid in a way that is worth reading. By default the tests expect to find a database at `jdbc:postgresql://localhost:5432/c3p0`, and the URL can be changed with `C3P0_TEST_JDBC_URL`. The README says c3p0's testing is, um, embarrassingly informal, that there is a junit test suite but it covers a very small fraction of c3p0 functionality, and it is run with `./mill test`. Mostly c3p0 is tested by running a few test applications and varying config ad hoc to see how things work, and the author adds that if you think c3p0 could and should be tested more professionally and automatically, me too, and that a pull request would be welcome. The load tests are the substantive part. `./mill test.c3p0Benchmark` runs through and times a bunch of different c3p0 operations, and is described as c3p0's most basic, common, test of first resort. `./mill test.c3p0Load` puts c3p0 under a load of 100 threads performing 1000 database operations each, then terminates. And `./mill test.c3p0PSLoad` puts c3p0 under load of 100 threads performing database operations indefinitely, using PreparedStatement so that it exercises the statement cache.

## Configuring a test run, and the examples

Test runs are configured from the environment rather than by editing `build.mill`, and the reasoning is that switching between setups rebuilds nothing. `C3P0_TEST_CONFIG` selects which properties file the tests see, `local` being the default and `rough` the other. `C3P0_TEST_JDBC_URL` overrides the default URL. `C3P0_TEST_USER` and `C3P0_TEST_PASSWORD` set the corresponding system properties, with the password allowed to be empty. `C3P0_TEST_JVM_ARGS` is a whitespace-separated list of extra JVM arguments appended last, which may define c3p0 properties directly. The `example/` directory shows the four DataSource flavours side by side, `UseJndiDataSource`, `UsePoolBackedDataSource`, `UseUnpooledDataSource` and `JndiBindDataSource`, plus a `c3p0-service.xml` for deployment as a service. There is also an `adding-properties.md` at the root and a `dev-notes.md` for the maintainer's own notes.

## Conclusion

Adopt c3p0 if you run a JDBC application that needs a connection pool and statement cache and you want the configuration surface of a library with a long production history. Skip it if your project already has a pool in its framework, since c3p0 duplicates what HikariCP or the Spring pool provide. Before you deploy, read the security note in the documentation, because the README states that c3p0 and its dependencies have been used as deserialization gadgets and that the vulnerabilities enabling that were addressed as of c3p0-0.12.0, so you need a version at or beyond that.

## FAQ

### Why does the c3p0 README warn about deserialization gadgets?

Because c3p0 and its dependencies have been used as deserialization gadgets. The vulnerabilities that enable this are addressed as of c3p0-0.12.0, 0.13.0 removed the javax.naming.Reference to Java serialization pipeline from the classpath, and 0.14.0 hardened JNDI and serialization utilities further. The README asks you to update your applications.

### How do I build c3p0 from source?

With the checked-in mill launcher, run `./mill jar` in the repository directory, which produces `out/jar.dest/out.jar`. You do not need to install mill yourself, since the launcher fetches the pinned version and a mill on your PATH may be too old to parse build.mill.

### How are c3p0 tests configured?

By environment variables rather than by editing the build file. C3P0_TEST_CONFIG selects the local or rough properties file, C3P0_TEST_JDBC_URL overrides the default jdbc:postgresql://localhost:5432/c3p0, and C3P0_TEST_USER, C3P0_TEST_PASSWORD and C3P0_TEST_JVM_ARGS set credentials and extra JVM arguments.

### What does c3p0 use for its prepared statement cache?

The library caches and reuses PreparedStatement objects, and there is a dedicated load test for it, ./mill test.c3p0PSLoad, which puts c3p0 under a load of 100 threads performing database operations indefinitely using PreparedStatement so that the statement cache is exercised.

## Sources

- [Issues](https://github.com/swaldman/c3p0/issues)
- [Project website](http://www.mchange.com/projects/c3p0)
- [README](https://github.com/swaldman/c3p0/blob/0.15.x/README.md)
- [swaldman/c3p0 on GitHub](https://github.com/swaldman/c3p0)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/swaldman-c3p0
