PostgreSQL

Install PostgreSQL β€” macOS, Windows, Linux & Docker

Thirdy Gayares
12 min read

🎯 What You Will Learn

This is lesson one of the PostgreSQL series: getting a real database server running on your machine β€” whatever that machine is. Madaling sundan: pick your OS section, copy the commands, and by the end you'll be typing SQL into a live PostgreSQL 16.

  • What PostgreSQL actually is, and an honest take on when to pick it over MySQL or SQLite
  • How to choose between a native installer, a package manager, and Docker
  • Install PostgreSQL 16 on macOS (Homebrew), Windows (EDB installer), Ubuntu/Debian (PGDG apt repo), or Docker (with a volume that keeps your data)
  • Make your first connection with psql and verify it with \conninfo and SELECT version();
  • Create your first database and a dedicated app user β€” the habit that saves you later
  • Fix the classic install errors: psql is not recognized, role does not exist, port already in use, password authentication failed

Prerequisites: none. This is the very first stop. You don't need to know any SQL yet β€” you just need a terminal and about fifteen minutes. Every error message in this post is real; I show you the failure first, then the fix, so when you hit it yourself you'll recognize it instead of panicking.

What PostgreSQL Is (and Why Real Teams Pick It)

PostgreSQL (or just "Postgres") is an open-source relational database server. It runs as a background service on a machine, listens on port 5432, and stores your data in tables you query with SQL. It's been in development since the 90s, it's free, and it powers production systems at companies of every size β€” from two-person startups to Instagram-scale platforms.

Why do experienced teams reach for it? Because it's strict where it matters. Postgres enforces your data types and constraints instead of silently "helping" you, it has first-class support for JSON, full-text search, and window functions, and its transactional behavior (MVCC) is rock solid. When your data is the business β€” orders, payments, user accounts β€” strict is exactly what you want.

The honest comparison: SQLite is a brilliant single-file library β€” perfect for mobile apps, prototypes, and small tools, but it's not a server, so concurrent writers and remote connections are not its game. MySQL is a fine server and you'll meet it everywhere, but historically it has been more permissive about silently truncating or coercing bad data, and its SQL feature set trails Postgres (though modern versions have closed much of the gap). For a backend career in 2026, PostgreSQL is the safest default: everything you learn here transfers to the others, but not always the reverse.

πŸ’‘
Mental model: PostgreSQL is a server, not a file. Installing it means putting a program on your machine that runs in the background 24/7, guards a data directory on disk, and accepts connections from clients β€” psql, your FastAPI app, a GUI β€” over port 5432. Everything in this tutorial is really just: start the server, then connect a client to it.

Pick Your Install Method

There are three sane ways to get Postgres on your machine. Wala itong "one true way" β€” they all give you the same database. Pick based on your OS and how you like to work:

MethodProsConsBest for
Native installer (EDB on Windows, Postgres.app on macOS)Guided GUI setup, bundles pgAdmin, auto-starts as a serviceVersion upgrades are manual, uninstall leaves tracesWindows users, and anyone who prefers clicking over typing
Package manager (Homebrew, apt)One command, easy upgrades, feels native to the OSSmall PATH/auth gotchas (we cover both below)macOS and Linux daily-driver dev machines
DockerIdentical on every OS, disposable, run many versions side by side, closest to productionYou must understand volumes or you will lose dataAnyone with Docker installed; teams sharing a compose file

My recommendation as a default: if you already have Docker Desktop running, use Docker β€” it matches how you'll run Postgres in CI and production later. If not, use your OS package manager (Homebrew / apt), or the EDB installer on Windows. Whatever you pick, jump to that section β€” you don't need to read the other OS sections.

πŸ’‘
Version note: this series standardizes on PostgreSQL 16. Newer majors (17+) work the same for everything we do here, but pinning one major version β€” instead of installing "whatever is latest today" β€” means your machine, your teammate's machine, and your server all behave the same. That habit alone prevents a whole category of "works on my machine" bugs.

macOS: Install with Homebrew

On macOS, Homebrew is the cleanest route. If you don't have Homebrew yet, install it first from brew.sh, then come back.

1Install the postgresql@16 formula
terminal
brew install postgresql@16
==> Downloading https://ghcr.io/v2/homebrew/core/postgresql/16/manifests/16.9
==> Pouring [email protected]_sequoia.bottle.tar.gz
==> Caveats
postgresql@16 is keg-only, which means it was not symlinked into /opt/homebrew,
because this is an alternate version of another formula.

If you need to have postgresql@16 first in your PATH, run:
  echo 'export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH"' >> ~/.zshrc

To start postgresql@16 now and restart at login:
  brew services start postgresql@16
==> Summary
🍺  /opt/homebrew/Cellar/postgresql@16/16.9: 3,770 files, 68.4MB
2Add psql to your PATH (keg-only gotcha)

Read that caveat carefully β€” postgresql@16 is keg-only, meaning Homebrew does not put psql on your PATH automatically. Run the echo line it suggests, then reload your shell:

terminal
echo 'export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
psql --version
psql (PostgreSQL) 16.9
⚠️
Intel Mac? Homebrew lives at /usr/local instead of /opt/homebrew, so your PATH line is export PATH="/usr/local/opt/postgresql@16/bin:$PATH". If psql --version says command not found after the echo, this mismatch is almost always why β€” check brew --prefix to confirm where your Homebrew actually is.
3Start the server as a background service
terminal
brew services start postgresql@16
==> Successfully started `postgresql@16` (label: homebrew.mxcl.postgresql@16)

brew services registers Postgres with launchd, so it also restarts automatically when you reboot. To check it later: brew services list. To stop it: brew services stop postgresql@16.

4Connect for the first time
terminal
psql postgres
psql (16.9)
Type "help" for help.

postgres=#
πŸ’‘
Homebrew quirk worth knowing: Homebrew creates the database superuser using your macOS username β€” there is no postgres user by default, and no password for local connections. That's why it's psql postgres (connect to the database named postgres as yourself), not psql -U postgres. If a tutorial or app expects a postgres superuser to exist, create one with createuser -s postgres.

Prefer an app over a service? Postgres.app is a great alternative: a menu-bar app you start and stop like any other Mac app, with all versions bundled. Nice for beginners; Homebrew is nicer once you live in the terminal.

Windows: The EDB Installer, Step by Step

On Windows the standard route is the EnterpriseDB (EDB) installer β€” it's the one linked from the official postgresql.org downloads page. It installs the server, psql, and pgAdmin in one go.

1Download the installer

Go to the downloads page, click Download the installer, and grab PostgreSQL 16 for Windows x86-64. You'll get a file like postgresql-16.9-1-windows-x64.exe.

2Run it and keep the default components

Launch the installer (accept the UAC prompt). On the Select Components screen, keep all four checked: PostgreSQL Server, pgAdmin 4, Stack Builder (optional extras β€” safe to uncheck), and Command Line Tools (this is psql β€” do not uncheck it).

3Set the postgres superuser password β€” and remember it

The installer asks for a password for the postgres superuser. This is the single most important screen. Pick something you will remember (for a learning machine, even devpassword123 is fine) and write it down β€” every future connection as postgres needs it.

4Keep port 5432 and the default locale

Accept port 5432 (the Postgres standard) and the default locale, click through, and let it install. When it offers to launch Stack Builder at the end, you can skip it.

5Try psql β€” and meet the classic Windows error

Open a fresh Command Prompt or PowerShell and type:

terminal
psql --version
'psql' is not recognized as an internal or external command,
operable program or batch file.
⚠️
Don't panic β€” nothing is broken. The EDB installer does not add psql to your PATH. The binaries are sitting in C:\Program Files\PostgreSQL\16\bin; Windows just doesn't know to look there yet. You have two fixes: use the bundled SQL Shell (psql) from the Start Menu (zero setup), or add the bin folder to PATH so psql works in any terminal β€” do the PATH fix, it takes one minute.
6Add psql to PATH permanently

Press Win + S, search "environment variables", open Edit the system environment variables β†’ Environment Variables…. Under System variables, select Path β†’ Edit β†’ New, and add:

Environment Variables β†’ Path β†’ New
C:\Program Files\PostgreSQL\16\bin

Click OK on every dialog, then open a new terminal (existing windows keep the old PATH) and verify:

terminal
psql --version
psql -U postgres
psql (PostgreSQL) 16.9

Password for user postgres:
psql (16.9)
WARNING: Console code page (437) differs from Windows code page (1252)
         8-bit characters might not work correctly. See psql reference
         page "Notes for Windows users" for details.
Type "help" for help.

postgres=#

That code-page warning is cosmetic β€” psql works fine. The server itself was registered as a Windows service named postgresql-x64-16, so it starts automatically with Windows. You can manage it from services.msc if you ever need to stop or restart it.

Linux: Ubuntu/Debian with the Official PGDG Repo

Ubuntu's default repositories carry Postgres, but often an older major version depending on your release. The habit worth building: install from PGDG β€” the PostgreSQL project's own apt repository β€” so you choose the exact major version and get updates straight from the source.

1Add the PGDG repository
terminal
sudo apt update
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
This script will enable the PostgreSQL APT repository on apt.postgresql.org on
your system. The distribution codename used will be noble-pgdg.

Press Enter to continue, or Ctrl-C to abort.

Using keyring /usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg
Writing /etc/apt/sources.list.d/pgdg.sources ...
Running apt-get update ...
You can now start installing packages from apt.postgresql.org.
2Install PostgreSQL 16
terminal
sudo apt install -y postgresql-16
Setting up postgresql-16 (16.9-1.pgdg24.04+1) ...
Creating new PostgreSQL cluster 16/main ...
/usr/lib/postgresql/16/bin/initdb -D /var/lib/postgresql/16/main --auth-local peer --auth-host scram-sha-256 --no-instructions
Ver Cluster Port Status Owner    Data directory              Log file
16  main    5432 online postgres /var/lib/postgresql/16/main /var/log/postgresql/postgresql-16-main.log

Note the last line: apt already created a cluster on port 5432, started it, and created a Linux system user called postgres that owns it. Confirm the service is up:

terminal
sudo systemctl status postgresql
● postgresql.service - PostgreSQL RDBMS
     Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; preset: enabled)
     Active: active (exited) since Fri 2026-07-17 10:42:11 PST; 1min 4s ago
   Main PID: 4821 (code=exited, status=0/SUCCESS)
3Try to connect β€” and hit the peer-auth gotcha

Naturally you now type psql. And Postgres greets you with this:

terminal
psql
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  role "juan" does not exist

Here juan is my Linux username β€” yours will show your own. The database is running fine; it just has no database user matching your Linux account.

πŸ’‘
Why this happens β€” peer authentication: on Linux, local socket connections use peer auth by default: Postgres asks the OS "who is this?" and logs you in as the database role with the same name as your Linux user. Fresh installs have exactly one role β€” postgres β€” so connecting as juan fails. The fix is to become the postgres system user for a moment.
4Connect as the postgres system user
terminal
sudo -u postgres psql
psql (16.9 (Ubuntu 16.9-1.pgdg24.04+1))
Type "help" for help.

postgres=#

You're in. In section 8 we'll create a proper database user for daily work so you don't live inside sudo -u postgres forever. If you also want password (TCP) logins as postgres β€” e.g., for a GUI client β€” set one now:

psql
ALTER USER postgres WITH PASSWORD 'devpassword123';
ALTER ROLE

Docker: The Same Postgres on Every Machine

If you have Docker, you can skip everything above and run the official image. This is my favorite for teaching because the command is identical on macOS, Windows, and Linux. Here's the naive version first:

terminal
docker run --name shop-postgres \
  -e POSTGRES_PASSWORD=devpassword123 \
  -p 5432:5432 \
  -d postgres:16
Unable to find image 'postgres:16' locally
16: Pulling from library/postgres
7ce705000c39: Pull complete
c690f0ee83f9: Pull complete
Digest: sha256:4ec37d2a07a0067f176fdcc9d4bb633a5724d2cc4f892c7a2046d054bb6939e5
Status: Downloaded newer image for postgres:16
8f3b2a91c4d75e02a6b1f9d8c3e47a10b52c96d40f8ea7315d90cb28a4e61f7c

Three flags doing all the work: -e POSTGRES_PASSWORD sets the password for the postgres superuser (the image refuses to start without it), -p 5432:5432 publishes the container's port to your machine so local tools can connect, and -d runs it in the background. It works β€” but there's a trap in it.

⚠️
Data-loss warning β€” this container has no volume. Postgres writes its data inside the container's filesystem. The day you run docker rm shop-postgres (or Docker Desktop resets), every database, table, and row is gone permanently. OK for a five-minute experiment β€” never OK for anything you care about. The fix is a named volume mounted at /var/lib/postgresql/data, which survives the container.
1Run it properly β€” with a named volume
terminal
docker rm -f shop-postgres   # remove the throwaway one first

docker run --name shop-postgres \
  -e POSTGRES_PASSWORD=devpassword123 \
  -p 5432:5432 \
  -v shop_pgdata:/var/lib/postgresql/data \
  -d postgres:16
2Confirm it is running
terminal
docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                    NAMES
9c1e5b2f8a3d   postgres:16   "docker-entrypoint.s…"   12 seconds ago   Up 11 seconds   0.0.0.0:5432->5432/tcp   shop-postgres

Now docker rm -f shop-postgres followed by the same docker run brings your data back intact, because the volume shop_pgdata outlives the container. Verify it exists with docker volume ls.

3Or better: write it down as docker-compose.yml

Flags in your shell history are easy to lose. A compose file is the same setup as reviewable, commit-able code β€” this is how teams share their local database setup:

shop-db/
└── docker-compose.yml   # the whole database setup, in one file
docker-compose.yml
services:
  postgres:
    image: postgres:16
    container_name: shop-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: devpassword123
      POSTGRES_DB: shop
    ports:
      - "5432:5432"
    volumes:
      - shop_pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d shop"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  shop_pgdata:
terminal
docker compose up -d
[+] Running 3/3
 βœ” Network shop-db_default   Created
 βœ” Volume "shop-db_shop_pgdata"  Created
 βœ” Container shop-postgres   Started

Bonus: POSTGRES_DB: shop pre-creates a database named shop on first start, and the healthcheck lets other services (your future FastAPI container) wait until Postgres is actually ready. To connect with psql inside the container β€” no local install needed:

terminal
docker exec -it shop-postgres psql -U postgres
psql (16.9 (Debian 16.9-1.pgdg120+1))
Type "help" for help.

postgres=#
⚠️
One Docker password gotcha to remember: POSTGRES_PASSWORD is only applied the first time the volume is initialized. If you later change it in docker-compose.yml and restart, the old password still applies β€” the data directory already exists, so the init step is skipped. Either change it with ALTER USER inside psql, or (dev only, destroys data) reset with docker compose down -v.

Your First Connection: psql, \conninfo, and version()

Whichever route you took, you now have a server. Let's make a deliberate, understood connection. psql is the official terminal client β€” it ships with every install and it's the tool every Postgres tutorial (including this whole series) assumes. Connect as the superuser:

terminal
# macOS (Homebrew):    psql postgres
# Windows / password:  psql -U postgres
# Linux (peer auth):   sudo -u postgres psql
# Docker:              docker exec -it shop-postgres psql -U postgres

psql -U postgres
Password for user postgres:
psql (16.9)
Type "help" for help.

postgres=#

Read the prompt: postgres=#. The word is the database you're connected to (a fresh install has a default database called postgres), and the # means you're a superuser. Regular users get => instead β€” you'll see that in the next section. First meta-command to learn: \conninfo, which tells you exactly where you're connected β€” invaluable when you have multiple Postgres installs running:

psql
\conninfo
You are connected to database "postgres" as user "postgres" on host "localhost" (address "127.0.0.1") at port "5432".

And your first actual SQL query β€” ask the server what it is:

psql
SELECT version();
                                                     version
------------------------------------------------------------------------------------------------------------------
 PostgreSQL 16.9 (Debian 16.9-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
(1 row)
βœ…
Milestone! If you see a version string and (1 row), you have a working PostgreSQL 16 server and a working client, at talking na sila. That's the whole point of this tutorial β€” everything from here is bonus. To leave psql, type \q and press Enter.

Create Your First Database and App User

Right now you have one database (postgres) and one all-powerful user. Production instinct says: apps should get their own database and a non-superuser account. Let's set up the shop database this series uses everywhere, plus a shop_app user. Connected as the superuser, run:

01_create_shop.sql
CREATE DATABASE shop;

CREATE USER shop_app WITH PASSWORD 'app_password_123';

GRANT CONNECT ON DATABASE shop TO shop_app;
CREATE DATABASE
CREATE ROLE
GRANT

(Postgres echoes CREATE ROLE for CREATE USER β€” a user is a role, just one with login permission.) Now switch into the new database and let shop_app actually build things in it:

psql
\c shop
You are now connected to database "shop" as user "postgres".
02_grant_schema.sql
GRANT USAGE, CREATE ON SCHEMA public TO shop_app;
GRANT
⚠️
Don't skip that schema grant. Since PostgreSQL 15, ordinary users can no longer create tables in the public schema by default β€” a security improvement that breaks many older tutorials. Without it, shop_app can connect but its first CREATE TABLE dies with ERROR: permission denied for schema public. If you ever see that error, this grant (run by the superuser, inside the target database) is the fix.

Exit with \q and reconnect as the new user β€” over TCP this time (-h localhost), so password auth applies on every platform:

terminal
psql -h localhost -U shop_app -d shop
Password for user shop_app:
psql (16.9)
Type "help" for help.

shop=>

Notice the prompt: shop=> β€” connected to shop, as a regular (non-super) user. Prove the privileges work end to end with a tiny table:

03_sanity_check.sql
CREATE TABLE connection_test (
  test_id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  note    TEXT NOT NULL
);

INSERT INTO connection_test (note) VALUES ('kaya na natin ito!');

SELECT test_id, note FROM connection_test;
CREATE TABLE
INSERT 0 1
 test_id |        note
---------+--------------------
       1 | kaya na natin ito!
(1 row)

Clean up the scratch table β€” the real schema comes in the next tutorial:

psql
DROP TABLE connection_test;
DROP TABLE
βœ…
You now have the setup every later post in this series assumes: a shop database and a shop_app user that can create tables in it. Your app connection string from here on is postgresql://shop_app:app_password_123@localhost:5432/shop β€” no superuser anywhere in it.

GUI Clients: pgAdmin, TablePlus, DBeaver

You don't need a GUI β€” this series teaches psql on purpose, because psql is on every server you'll ever SSH into. But a GUI genuinely helps when you're exploring an unfamiliar schema, eyeballing rows in a wide table, or editing data by hand. The three worth knowing:

ClientPriceStrengthsPick it if…
pgAdminFree, open sourcePostgres-only and deep: query plans, server stats, role management. Already installed by the EDB Windows installer.You want the official, does-everything tool for free
TablePlusFree tier; paid licenseFast native app, clean UI, inline row editing, multi-database (Postgres, MySQL, SQLite…)You are on macOS/Windows and value a polished daily driver
DBeaverFree, open source (Community)Runs everywhere (Java), huge database support, solid ER diagrams and data exportYou touch many database engines, or you are on Linux

Whichever you choose, the connection settings are the same ones you've been using: host localhost, port 5432, database shop, user shop_app, and your password. If the GUI can't connect but psql can, compare against \conninfo β€” nine times out of ten it's a wrong port or a wrong database name.

Troubleshooting: The Four Errors Everyone Hits

Ito ang section na babalikan mo. Four real errors, exactly as Postgres prints them, and what each one actually means.

1Port 5432 is already in use
docker: Error response from daemon: driver failed programming external connectivity on endpoint shop-postgres: Bind for 0.0.0.0:5432 failed: port is already allocated.

Something on your machine already owns port 5432 β€” usually a second Postgres you forgot about (Homebrew service + Docker container is the classic combo). Find the culprit:

terminal
# macOS / Linux
lsof -i :5432

# Windows (PowerShell)
netstat -ano | findstr :5432
COMMAND   PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
postgres  731  thirdy   7u  IPv6 0x9a2f...      0t0  TCP localhost:postgresql (LISTEN)

Then either stop the other server (brew services stop postgresql@16 / sudo systemctl stop postgresql), or run the new one on a different host port, e.g. -p 5433:5432 in Docker and connect with psql -h localhost -p 5433 -U postgres.

⚠️
Running two Postgres servers without realizing it is the #1 source of "my table disappeared!" panic for beginners. The table didn't disappear β€” you created it on the Homebrew server and you're now connected to the Docker one. When in doubt, \conninfo and check the port.
2Password authentication failed
psql: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  password authentication failed for user "postgres"

The server is up; your credentials are wrong. Check in this order: (1) typo in the password, (2) wrong user β€” on Homebrew the superuser is your macOS username, not postgres, (3) wrong server β€” see the two-servers trap above, (4) Docker: you changed POSTGRES_PASSWORD after the volume was initialized, so the old password still applies. If you're truly locked out on a dev machine, connect via a channel that skips passwords (sudo -u postgres psql on Linux, docker exec -it shop-postgres psql -U postgres on Docker) and reset it:

psql
ALTER USER postgres WITH PASSWORD 'devpassword123';
ALTER ROLE
3No such file or directory β€” the server is not running
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
        Is the server running locally and accepting connections on that socket?

psql found no server at all. Nothing is listening β€” the service is stopped. Start it with your platform's command and retry:

terminal
# macOS
brew services start postgresql@16

# Linux
sudo systemctl start postgresql

# Docker
docker start shop-postgres

# Windows: services.msc -> postgresql-x64-16 -> Start
4Connection refused
psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?

Similar smell, different meaning: you reached the machine over TCP, but nothing is listening on that port. Usual suspects: the Docker container is running but you forgot -p 5432:5432 (check docker ps β€” the PORTS column must show 0.0.0.0:5432->5432/tcp), you're connecting to the wrong port after remapping to 5433, or the service crashed on startup β€” check the logs (docker logs shop-postgres, or /var/log/postgresql/ on Linux).

Quick reference for when you meet these again:

Error says…It means…Fix
port is already allocated / Address already in useAnother server owns 5432lsof -i :5432, stop it or remap ports
password authentication failedServer up, credentials wrongCheck user/password/server; reset via a password-less channel
No such file or directoryService not runningbrew services / systemctl / docker start
Connection refusedNothing listening on that host:portPublish the port, check the port number, read the logs
role "yourname" does not existLinux peer auth, no matching rolesudo -u postgres psql
permission denied for schema publicPG15+ default, user lacks schema rightsGRANT USAGE, CREATE ON SCHEMA public TO ...;

Best Practices From Day One

None of these take extra effort today, and every one of them saves you a bad afternoon later. Sanayin mo na habang maaga:

βœ…
Install-day checklist:
  • Pin a major version β€” postgres:16, postgresql@16, postgresql-16 β€” never "latest". Upgrading a major version is a deliberate event, not a surprise.
  • Docker always gets a named volume at /var/lib/postgresql/data. No volume, no data β€” it's that binary.
  • Apps never connect as the postgres superuser. One dedicated user per app (shop_app), with only the privileges it needs. A bug in app code should not be able to drop other databases.
  • Passwords live in environment variables / a .env file, never hardcoded in code or committed to git β€” even the dev ones, so the habit is automatic when it matters.
  • Keep 5432 off the public internet. Locally that's the default (localhost only); on servers, keep the port firewalled and let only your app network reach it.
  • Know where your data directory is (SHOW data_directory; in psql) β€” the day you need backups or debugging, you won't be guessing.
⚠️
About that devpassword123: perfectly fine on a laptop where Postgres only listens on localhost β€” this is a learning box. On anything reachable from a network, generate a long random password and treat the superuser account like the root account it is. OK for learning; different game in production.

Practice Exercise + What's Next

Cement the muscle memory with one full round trip β€” no copy-paste from the sections above if kaya mo. All the commands appeared in this post:

  1. Connect to your server as the superuser and run \conninfo to confirm host and port.
  2. Create a database called practice_db and a user practice_user with a password.
  3. Grant it CONNECT on the database, plus USAGE, CREATE on schema public (remember to \c practice_db first!).
  4. Reconnect as practice_user with psql -h localhost -U practice_user -d practice_db.
  5. Create any small table, insert one row, select it back β€” then clean up by dropping the table.

Expected checkpoints along the way:

CREATE DATABASE
CREATE ROLE
GRANT
You are now connected to database "practice_db" as user "postgres".
GRANT
-- and after reconnecting, the non-superuser prompt:
practice_db=>
-- and your select returns your row with:
(1 row)

If you can do that loop without looking, you understand more about Postgres setup than many people who've used it for years β€” most devs only ever see a connection string someone else wrote.

βœ…
πŸš€ What's next in the PostgreSQL series:
  • psql Basics β€” drive the client like a pro: \l, \dt, \d table, history, and output formatting
  • Create Databases & Tables β€” design the full shop schema (customers, products, orders) with proper types and constraints
  • PostgreSQL Cheatsheet β€” the whole SQL surface on one page, for when you just need the syntax

Recap: you picked an install method with open eyes, put PostgreSQL 16 on your machine (or in a container with a volume), made a verified first connection, and created a database plus a non-superuser app account β€” with the real error messages already demystified. Your server is running quietly in the background now. Next stop: actually talking to it fluently.

About the Author

TG

Thirdy Gayares

Passionate developer creating custom solutions for everyone. I specialize in building user-friendly tools that solve real-world problems while maintaining the highest standards of security and privacy.