deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

PostgreSQL 18 on OpenBSD fails initdb until kernel semaphore limits are raised

A dev.to walkthrough shows PostgreSQL 18 aborting initdb on OpenBSD with a misleading disk-space error. The real cause is the kernel's low semaphore defaults, fixed by raising kern.seminfo.semmni and kern.seminfo.semmns.

PostgreSQL 18 on OpenBSD fails initdb until kernel semaphore limits are raised

A clean install that fails at the first step

Anyone deploying PostgreSQL 18 on OpenBSD from packages will hit a wall during initialization, according to a walkthrough published on dev.to. Installing the server with pkg_add postgresql-server works normally, but the first attempt to create a database cluster — running initdb as the _postgresql user against a fresh data directory under /var/postgresql — aborts with a FATAL error: "could not create semaphores: No space left on device".

The message is misleading, and PostgreSQL's own hint text in the log points this out: it is not a disk space problem. The failure happens when the kernel's limit on the maximum number of semaphore sets (SEMMNI), or the system-wide maximum number of semaphores (SEMMNS), would be exceeded.

There is a second, quieter symptom visible in the failed run. Before crashing during the bootstrap script, initdb had already scaled back its defaults to just 20 max connections and 400kB of shared buffers — a sign that PostgreSQL detected the tight kernel limits and tried to shrink itself to fit. It was not enough, and initdb deleted the partially built data directory on the way out.

Raising the semaphore limits

The fix is two sysctl commands:

doas sysctl kern.seminfo.semmni=256 doas sysctl kern.seminfo.semmns=2048

On the author's machine this moved the semaphore-set ceiling from 10 to 256 and the total-semaphore ceiling from 60 to 2048. OpenBSD ships with defaults far below what a modern PostgreSQL instance wants, and the database's semaphore consumption scales with its connection count — the same hint text suggests lowering max_connections as an alternative to touching the kernel.

With the new limits in place, the second initdb run completes cleanly. This time PostgreSQL selects the standard defaults of 100 connections and 128MB of shared buffers, chooses POSIX as its dynamic shared memory implementation, and enables data page checksums.

A few details from the successful run deserve attention. The cluster is initialized with locale C and SQL_ASCII encoding, and initdb emits a warning that "trust" authentication is enabled for local connections — worth changing via pg_hba.conf or the -A, --auth-local and --auth-host options if the server will be reachable beyond the local machine. The psql prompt in the guide reports version 18.6.

Making the change survive a reboot

Sysctl values set at runtime do not persist across reboots, so the guide appends both settings to /etc/sysctl.conf:

echo "kern.seminfo.semmni=256" | doas tee -a /etc/sysctl.conf echo "kern.seminfo.semmns=2048" | doas tee -a /etc/sysctl.conf

One small caveat for anyone copying the commands: the second line as printed in the original post carries the word "sysctl" in front of the assignment, which is not the format /etc/sysctl.conf expects — the file takes plain variable=value entries, so the prefix should be dropped.

After that, rcctl start postgresql brings the server up, and connecting with psql as the _postgresql user lands on a working prompt.

Why it matters

This is a small fix, but it sits at the intersection of two design philosophies. OpenBSD's conservative defaults — 10 semaphore sets and 60 semaphores system-wide — suit its minimal, secure-by-default posture, but they predate database servers that want a semaphore for every connection slot. Most Linux distributions ship kernels tuned high enough that PostgreSQL users never see this class of error; on OpenBSD it is the first thing you meet.

The silent downgrade behavior is the part worth remembering. Before failing outright, initdb had already cut its defaults to a fifth of the normal connection count and a tiny buffer pool. On a system that just barely squeaked under the limit, you could end up with a running but pathologically small database and no obvious error explaining why.

For anyone automating OpenBSD deployments, the practical takeaway is to bake these sysctls into the base image or configuration management from the start, rather than discovering them through a failed initdb.

  • #postgresql
  • #openbsd
  • #database
  • #sysadmin
  • #how-to