# Run the server

> Start postmaster with -D, socket/TCP flags, mandatory io_method=sync and stack settings, connect with psql, and confirm readiness.

- Repository: malisper/pgrust
- GitHub: https://github.com/malisper/pgrust
- Human docs: https://grok-wiki.com/public/docs/malisper-pgrust-7e0c8e82bc21
- Complete Markdown: https://grok-wiki.com/public/docs/malisper-pgrust-7e0c8e82bc21/llms-full.txt

## Source Files

- `README.md`
- `scripts/run-regression`
- `docker/entrypoint.sh`
- `crates/backend/postmaster/postmaster/src/main_entry.rs`
- `crates/backend/main/main_main/src/help.rs`
- `crates/backend/storage/buffer/bufmgr/src/buf_aio.rs`

---

---
title: "Run the server"
description: "Start postmaster with -D, socket/TCP flags, mandatory io_method=sync and stack settings, connect with psql, and confirm readiness."
---

With no dispatch-mode flag first (`--single`, `--boot`, `--check`, `--initdb`), `target/release/postgres` enters postmaster mode: `PostmasterMain` validates `PGDATA`, binds TCP and Unix sockets from `listen_addresses` / `unix_socket_directories`, forks checkpointer/bgwriter/startup, then blocks in `ServerLoop`. Operational boots used in the README, Docker entrypoint, and `scripts/run-regression` all pass `-c io_method=sync` and raise process/Rust/GUC stack limits before accepting clients.

<Warning>
pgrust is not production-ready. Always pass `-c io_method=sync` for local and Docker runs. The compiled default `io_method` is `worker` (`DEFAULT_IO_METHOD`); selecting `io_uring` panics as unported. Buffer-manager AIO read paths are documented for the synchronous method.
</Warning>

## Prerequisites

| Requirement | Detail |
| --- | --- |
| Binary | `target/release/postgres` from a release build, or the Docker image binary |
| Data directory | Existing cluster with `global/pg_control` (create with `postgres --initdb` first) |
| Non-root OS user | `check_root` refuses effective uid 0 and mismatched real/effective uids |
| Client | PostgreSQL 18 `psql` on `PATH` (or `PGRUST_PSQL` for harnesses) |
| Stack headroom | `ulimit -s 65520` and `RUST_MIN_STACK=33554432` before start |

## Mandatory runtime settings

These values appear in README start instructions, `docker/entrypoint.sh` (`PGRUST_SERVER_OPTS`), and `scripts/run-regression`.

| Setting | Value | Role |
| --- | --- | --- |
| Shell `ulimit -s` | `65520` | Raise OS stack so deep backend frames do not SIGSEGV |
| `RUST_MIN_STACK` | `33554432` (32 MiB) | Rust thread stack floor for the server process |
| `-c io_method` | `sync` | Force synchronous AIO method (overrides boot default `worker`) |
| `-c max_stack_depth` | `60000` (kB) | GUC stack budget used by harnesses/Docker (process default is `2048` kB) |

```bash
ulimit -s 65520
export RUST_MIN_STACK=33554432
```

<Note>
`max_stack_depth` process default is intentionally `2048` (not C’s `100`) because Rust frames plus seam indirection deepen call chains. Harnesses still raise it further to `60000` / `7000` depending on path.
</Note>

## Start postmaster

### Recommended local command

Socket-only (no TCP), fsync off, short Unix socket path — matches the documented source-build path:

```bash
ulimit -s 65520

RUST_MIN_STACK=33554432 target/release/postgres \
  -D /tmp/pgrust-data \
  -F \
  -c listen_addresses= \
  -k /tmp \
  -p 5432 \
  -c io_method=sync \
  -c max_stack_depth=60000
```

### Flag map

| Flag / option | Sets | Notes |
| --- | --- | --- |
| `-D DATADIR` | Data directory | Required; postmaster selects config, chdirs, lockfile |
| `-k DIRECTORY` | `unix_socket_directories` | Default GUC boot value is `/tmp` |
| `-p PORT` | `port` | Default client/server port is `5432` |
| `-h HOSTNAME` | `listen_addresses` | TCP bind list |
| `-i` | `listen_addresses=*` | Deprecated enable-TCP form |
| `-c listen_addresses=` | Empty TCP list | Socket-only; common for local/dev |
| `-c listen_addresses=*` | All interfaces | Docker final server injects this |
| `-F` | `fsync=false` | Dev convenience; not for durable production |
| `-c NAME=VALUE` / `--NAME=VALUE` | Any GUC | Postmaster context for most boot-time settings |
| `-c io_method=sync` | AIO method | **Required** for the supported operational path |
| `-c max_stack_depth=60000` | Stack GUC | Matches Docker / regression |

### Regression harness start line

`scripts/run-regression` backgrounds the same shape with a short socket dir under `/tmp` (macOS `sun_path` length) and extra GUCs:

```bash
"$PGRUST_BIN" -D "$DATADIR" -F -c listen_addresses= -k "$SOCK" -p "$PORT" \
  -c io_method=sync -c max_stack_depth=60000 \
  -c checkpoint_timeout=3600 -c autovacuum=on \
  -c max_logical_replication_workers=0
```

Default harness port is `55434` (`PGPORT`).

### Docker final exec

After first-boot init, the entrypoint rewrites `postgres …` to the pgrust binary and always injects:

```text
-c io_method=sync
-c max_stack_depth=60000
-c unix_socket_directories=/var/run/postgresql
-c listen_addresses='*'
```

Temp init servers use the same `PGRUST_SERVER_OPTS` with `listen_addresses=''` (socket-only).

## What PostmasterMain does

```text
argv (default mode)
        │
        ▼
  check_root (refuse uid 0)
        │
        ▼
  PostmasterMain
   ├─ InitProcessGlobals, signal handlers, GUC init
   ├─ process_postgres_switches (-D, -k, -p, -c …)
   ├─ SelectConfigFiles + checkDataDir + pg_control present
   ├─ CreateSharedMemoryAndSemaphores
   ├─ establish_input_sockets
   │     listen_addresses  → TCP ListenServerPort
   │     unix_socket_directories → AF_UNIX ListenServerPort
   ├─ PM_STARTUP + checkpointer / bgwriter / startup children
   └─ ServerLoop()  (never returns)
              │
              ▼  (after recovery)
   log: "database system is ready to accept connections"
```

Missing every listen socket is fatal: `no socket created for listening`. Missing `global/pg_control` exits after a diagnostic naming the expected path.

## Connect with psql

### Unix socket (local recommended)

```bash
psql -h /tmp -p 5432 -U postgres -d postgres \
  -c "select version(), 1 + 1 as two"
```

Match `-h` to the directory from `-k` / `unix_socket_directories`.

### TCP

Only if the server listens on TCP (`listen_addresses` non-empty) and `pg_hba.conf` allows the method:

```bash
psql -h 127.0.0.1 -p 5432 -U postgres -d postgres
```

<Warning>
Docker defaults `POSTGRES_HOST_AUTH_METHOD` to `trust` for host lines because password authentication (`fetch_role_password`) is not fully ported. Forcing scram/md5 host methods yields FATAL seam errors on TCP logins even with a correct password. Local/unix `trust` remains the reliable path for clients.
</Warning>

## Confirm readiness

<Steps>
  <Step title="Process still alive">
    After backgrounding the postmaster, ensure the PID has not exited. Harnesses treat early death as boot failure and print the tail of the postmaster log.
  </Step>
  <Step title="Poll a trivial query">
    Readiness is defined by accepting a successful SQL session, not by a separate control protocol:

```bash
psql -h /tmp -p 5432 -U postgres -d postgres -c 'SELECT 1'
```

    Regression waits up to ~80s (`160 × 0.5s`). Docker temp-server start polls up to 120 iterations of 0.5s against the Unix socket under `/var/run/postgresql`.
  </Step>
  <Step title="Optional log line">
    After recovery completes, the reaper path logs:

```text
database system is ready to accept connections
```

    Hot-standby promotion may log readiness for read-only connections instead.
  </Step>
  <Step title="Smoke SQL">
```bash
psql -h /tmp -p 5432 -U postgres -d postgres \
  -c "select version(), 1 + 1 as two"
```
  </Step>
</Steps>

<Check>
A non-zero `psql` exit, connection refused, or “postmaster died during boot” means the cluster is not ready — inspect the postmaster stderr/log for GUC, share-dir, stack, or control-file errors.
</Check>

## Stop the server

| Signal | Effect (as used in-repo) |
| --- | --- |
| `SIGINT` | Fast shutdown path used by Docker temp-server stop |
| `SIGTERM` / `SIGQUIT` | Postmaster shutdown handlers (same signal set as C postmaster) |
| Harness cleanup | `kill` then escalate to `kill -9` if the PID lingers |

There is no separate `pg_ctl` wrapper in the clone-only path; send signals to the postmaster PID directly.

## Failure modes at start

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Boot fails / AIO issues without `io_method=sync` | Default `worker` or other method not suitable for current operational path | Always pass `-c io_method=sync` |
| Panic mentioning `io_uring` | Unsupported method selected | Use `sync` only |
| Stack overflow / “stack depth limit exceeded” | Low OS stack, missing `RUST_MIN_STACK`, or low `max_stack_depth` | `ulimit -s 65520`, `RUST_MIN_STACK=33554432`, `-c max_stack_depth=60000` |
| `"root" execution of the PostgreSQL server is not permitted` | Started as uid 0 | Run as an unprivileged user (Docker uses `gosu postgres`) |
| `could not find the database system: expected to find pg_control at …` | Empty or wrong `-D` | Init with `--initdb` or point `-D` at a valid PG 18.3 data dir |
| `no socket created for listening` | Empty/failed `listen_addresses` and `unix_socket_directories` | Set `-k` / Unix dirs and/or TCP listen list |
| Unix socket connect fails on macOS | Socket path longer than `sun_path` | Use a short `-k` directory under `/tmp` (as regression does) |
| Wrong timezone / share files | Share tree not baked or wrong at init | Build with `PGRUST_PGSHAREDIR`; init with `-L` to vendored share |
| TCP auth FATAL `fetch_role_password` | Password host auth unported | Prefer unix socket or `trust` host method |

## Related pages

<CardGroup cols={2}>
  <Card title="Initialize a cluster" href="/init-cluster">
    Create PGDATA with `postgres --initdb` before first start.
  </Card>
  <Card title="Configuration reference" href="/configuration-reference">
    `io_method`, stack GUCs, listen settings, and build-time path env vars.
  </Card>
  <Card title="postgres CLI reference" href="/cli-reference">
    Full `--help` flags and GUC override forms.
  </Card>
  <Card title="Docker" href="/docker">
    Image entrypoint injects the same mandatory opts and readiness polling.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Stack, share path, root, and missing-client failures in one place.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    Shortest build → init → start → `version()` path.
  </Card>
</CardGroup>
