PostgreSQL Database Creation and Management
A database is PostgreSQL's top-level organizational unit — like a filing cabinet that can hold many drawers (tables).
1. What You'll Learn
- CREATE DATABASE to create a database
- DROP DATABASE to drop a database
- ALTER DATABASE to modify database properties
- Template databases (template0 / template1)
- Character set and collation
- psql meta-commands: \l / \c
2. A DevOps Engineer's Real Story
(1) The Pain: Three Environments, Three Character Sets
Charlie needs to create 3 databases for an e-commerce project, corresponding to the dev / staging / prod environments:
- dev: English collation (convenient for development)
- staging: UTF8 + English collation (consistent with production)
- prod: UTF8 + a specific collation (Middle East market, needs Arabic support)
Charlie is unsure how to specify the character set and collation when creating a database, and doesn't know what a template database is.
(2) CREATE DATABASE to the Rescue
PostgreSQL's CREATE DATABASE lets you specify the character set, collation, and template at creation time:
-- Create databases with different locales for each environment
CREATE DATABASE shop_dev
WITH ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
TEMPLATE = template1;
CREATE DATABASE shop_staging
WITH ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8';
CREATE DATABASE shop_prod
WITH ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8';
(3) The Payoff
- Each environment has its own independent database; data doesn't interfere
- Character set unified to UTF8, supporting multilingual data
- Collation matches the business need, so query result order is correct
3. Database Fundamentals
(1) PostgreSQL's Organizational Hierarchy
graph TB
PG[PostgreSQL Instance<br/>One running server] --> DB1[Database: shop_dev]
PG --> DB2[Database: shop_staging]
PG --> DB3[Database: shop_prod]
DB1 --> SC1[Schema: public]
SC1 --> T1[Table: users]
SC1 --> T2[Table: orders]
DB2 --> SC2[Schema: public]
DB3 --> SC3[Schema: public]
| Level | Description | Cardinality |
|---|---|---|
| Instance | One running PostgreSQL server process | 1 instance contains many databases |
| Database | The top-level independent namespace | 1 database contains many schemas |
| Schema | A namespace within a database (default public) | 1 schema contains many tables |
| Table | A two-dimensional table storing data | Tables belong to a schema |
4. CREATE DATABASE
(1) Basic Syntax
CREATE DATABASE name
[WITH]
[OWNER = user_name]
[TEMPLATE = template]
[ENCODING = encoding_name]
[LC_COLLATE = lc_collate]
[LC_CTYPE = lc_ctype]
[TABLESPACE = tablespace_name]
[CONNECTION LIMIT = conn_limit]
[IS_TEMPLATE = true | false];
| Parameter | Default | Description |
|---|---|---|
OWNER |
The executing user | Database owner |
TEMPLATE |
template1 | The template copied when creating a new database |
ENCODING |
Template's encoding | Character encoding (UTF8 recommended) |
LC_COLLATE |
Template's collation | String sort order |
LC_CTYPE |
Template's character classification | Character classification (case/digits/etc.) |
TABLESPACE |
Default tablespace | Data-file storage location |
CONNECTION LIMIT |
-1 (unlimited) | Max concurrent connections |
IS_TEMPLATE |
false | Mark as a template database |
▶ Example: Create a Basic Database
-- Create a simple database with default settings
CREATE DATABASE my_app;
-- Verify creation
\l
Output:
CREATE TABLE
▶ Example: Create a Database with Full Parameters
-- Create database with all common options specified
CREATE DATABASE shop_prod
WITH OWNER = devuser
ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
CONNECTION LIMIT = 100;
Output:
CREATE TABLE
5. Template Databases
(1) template0 vs template1
PostgreSQL ships with two built-in template databases:
| Property | template0 | template1 |
|---|---|---|
| Purpose | Pristine template, not modifiable | Customizable template, modifiable |
| Modifiable? | ❌ No | ✅ Yes |
| Default contents | Minimal system objects | Same as template0 + user-defined objects |
| When to use | When you need to restore original encoding/collation | Daily database creation (default) |
| Creation | TEMPLATE = template0 |
TEMPLATE = template1 (default) |
▶ Example: Pre-Configure a Database with Templates
-- Step 1: Connect to template1 and add common extensions
\c template1
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
-- Step 2: Now all new databases will have these extensions
\c postgres
CREATE DATABASE new_project;
-- new_project automatically has uuid-ossp and pg_trgm
-- Step 3: Verify
\c new_project
\dx
Output:
CREATE TABLE
▶ Example: Rebuild Encoding with template0
-- If template1 has a different encoding than you need,
-- use template0 to create a database with specific encoding
CREATE DATABASE db_with_latin
TEMPLATE = template0
ENCODING = 'LATIN1'
LC_COLLATE = 'C'
LC_CTYPE = 'C';
Output:
CREATE TABLE
6. ALTER DATABASE
(1) Common Modifications
| Operation | Syntax | Description |
|---|---|---|
| Rename | ALTER DATABASE old_name RENAME TO new_name |
Change the database name |
| Set parameter | ALTER DATABASE name SET parameter = value |
Set a runtime parameter for the database |
| Reset parameter | ALTER DATABASE name RESET parameter |
Restore the parameter's default |
| Change owner | ALTER DATABASE name OWNER TO new_owner |
Change the database owner |
| Set connection limit | ALTER DATABASE name CONNECTION LIMIT = n |
Change the max connection count |
| Mark as template | ALTER DATABASE name IS_TEMPLATE = true |
Mark / unmark as a template |
▶ Example: Modify Database Properties
-- Rename a database (must disconnect all users first)
ALTER DATABASE shop_dev RENAME TO shop_development;
-- Set default search_path for a database
ALTER DATABASE shop_prod SET search_path TO public, admin;
-- Set work_mem for a specific database
ALTER DATABASE shop_prod SET work_mem = '64MB';
-- Change connection limit
ALTER DATABASE shop_prod CONNECTION LIMIT = 200;
-- Mark as template
ALTER DATABASE shop_base IS_TEMPLATE = true;
Output:
-- SQL statement executed successfully
-- Find active connections to a database
SELECT pid, usename, application_name, client_addr, state
FROM pg_stat_activity
WHERE datname = 'shop_dev';
7. DROP DATABASE
(1) Drop Syntax
DROP DATABASE [IF EXISTS] name [WITH (FORCE)];
| Option | Description |
|---|---|
IF EXISTS |
No error if the database doesn't exist (only a notice) |
WITH (FORCE) |
Force-disconnect all connections, then drop (PG 13+) |
▶ Example: Drop a Database
-- Safe delete (no error if database doesn't exist)
DROP DATABASE IF EXISTS old_project;
-- Force delete (disconnect all users first, PG 13+)
DROP DATABASE IF EXISTS shop_dev WITH (FORCE);
Output:
-- SQL statement executed successfully
8. Character Set and Collation
(1) Common Character Encodings
| Encoding | Description | Recommended scenario |
|---|---|---|
| UTF8 | Unicode, supports all languages | All projects (recommended) |
| LATIN1 | Western European languages | Legacy system compatibility |
| EUC_JP | Japanese | Legacy Japanese systems |
| SQL_ASCII | No encoding conversion | Pure ASCII data |
(2) Collation Comparison
| Collation | Behavior | Example |
|---|---|---|
en_US.utf8 |
English sort, case-sensitive | A, a, B, b |
C |
Byte-order sort, fastest | A, B, a, b |
en_US.utf8 (with ICU) |
More flexible sorting | Can ignore case/accents |
▶ Example: View Encodings and Collations Supported by the System
-- List available encodings
SELECT name, description FROM pg_encodings LIMIT 10;
-- List available collations
SELECT name, locale FROM pg_collation LIMIT 10;
Output:
id | name | value
----+----------+-------
1 | example | 42
(1 row)
▶ Example: How Collation Affects Query Results
-- Create a test table with text data
CREATE TABLE sort_test (name TEXT);
INSERT INTO sort_test VALUES ('apple'), ('Banana'), ('cherry'), ('Apple');
-- Sort with C locale (byte order: uppercase first)
SELECT name FROM sort_test ORDER BY name COLLATE "C";
-- Sort with en_US.utf8 (dictionary order: case-insensitive within same letter)
SELECT name FROM sort_test ORDER BY name COLLATE "en_US.utf8";
-- Clean up
DROP TABLE sort_test;
Output:
-- C locale:
Apple
Banana
apple
cherry
-- en_US.utf8:
apple
Apple
Banana
cherry
9. psql Database Management Meta-Commands
| Command | Equivalent SQL | Description |
|---|---|---|
\l |
SELECT * FROM pg_database |
List all databases |
\l+ |
Same, with tablespace/size | List databases in detail |
\c dbname |
- | Switch to the specified database |
\conninfo |
- | Show current connection info |
▶ Example: Manage Databases in psql
# List all databases
\l
# Switch to shop_dev database
\c shop_dev
# Check current connection
\conninfo
# Switch back to postgres database
\c postgres
Output:
# command executed successfully
10. Complete Example: Three-Environment Database Setup
-- ============================================
-- Complete example: set up dev/staging/prod databases
-- For an e-commerce project
-- ============================================
-- Step 1: Connect to postgres (maintenance database)
\c postgres
-- Step 2: Create dev database with English locale
CREATE DATABASE shop_dev
WITH ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
OWNER = devuser
CONNECTION LIMIT = 50;
-- Step 3: Create staging database (same config as prod)
CREATE DATABASE shop_staging
WITH ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
OWNER = devuser
CONNECTION LIMIT = 50;
-- Step 4: Create prod database with connection limit
CREATE DATABASE shop_prod
WITH ENCODING = 'UTF8'
LC_COLLATE = 'en_US.utf8'
LC_CTYPE = 'en_US.utf8'
OWNER = devuser
CONNECTION LIMIT = 200;
-- Step 5: Set default search_path for prod
ALTER DATABASE shop_prod SET search_path TO public, admin;
-- Step 6: Verify all databases created
SELECT datname, pg_encoding_to_char(encoding) AS encoding,
datcollate, datctype, datconnlimit
FROM pg_database
WHERE datname LIKE 'shop_%'
ORDER BY datname;
Output:
datname | encoding | datcollate | datctype | datconnlimit
--------------+----------+--------------+--------------+-------------
shop_dev | UTF8 | en_US.utf8 | en_US.utf8 | 50
shop_prod | UTF8 | en_US.utf8 | en_US.utf8 | 200
shop_staging | UTF8 | en_US.utf8 | en_US.utf8 | 50
❓ FAQ
TEMPLATE = template0 instead.SELECT pg_size_pretty(pg_database_size('shop_dev')) for a single database, or \l+ to see all database sizes.📖 Summary
- CREATE DATABASE creates a database, supporting encoding/collation/template/owner/connection-limit
- template0 is a pristine template (not modifiable); template1 is a customizable template (the default)
- Install extensions in template1 and new databases automatically inherit them
- ALTER DATABASE can rename, set parameters, and change the owner
- DROP DATABASE is irreversible; IF EXISTS prevents errors, WITH (FORCE) force-disconnects
- Always use UTF8 encoding; choose collation based on business needs
- psql meta-commands:
\llists databases,\cswitches database,\conninfoshows connection info
📝 Exercises
-
Basic (★): Create a database named
my_bookstoreusing UTF8 encoding, then verify with\lthat it was created, and finally drop it. -
Intermediate (★★): First install the
uuid-osspextension in template1, then create a new databasetest_templateand verify that the new database has automatically inherited the uuid-ossp extension. -
Challenge (★★★): Create two databases using the
Canden_US.utf8collations respectively. In each, create the same table and insert the data'apple','Banana','cherry','Apple', then use ORDER BY to compare the sorting results and explain why they differ.



