Skip to content

Getting Started

This chapter walks through a complete working setup from scratch, in seven steps.

Step 1 — Give the pgrelay role a login

The pgrelay role (a database user account) is created by the extension with no ability to log in, as a security precaution. You need to enable it:

ALTER ROLE pgrelay WITH LOGIN PASSWORD 'choose-a-strong-password';

Then add the password to a .pgpass file so the Processor can connect without putting a password in the environment. See the PostgreSQL documentation for the exact .pgpass file format.

On Linux, if you are connecting over a Unix socket (a local, file-based connection rather than a network one), you can use peer authentication in pg_hba.conf instead, which needs no password at all.

Do not add any other privileges to the pgrelay role

It is intentionally limited — it can only call the specific functions it needs to process events, and it has no direct access to any table. This is a deliberate security boundary; see The Security Model in the Technical Guide.

Step 2 — Grant access to the management functions

Only pgrelay.notify() is available to every role by default. To register channels and manage them, grant your admin role the management functions.

The easiest way is to use grant_user():

SELECT pgrelay.grant_user('my_admin_role');

Or grant individual functions if you need finer control:

GRANT EXECUTE ON FUNCTION pgrelay.register(text, text, text, boolean, int, text, text, boolean) TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.update(text, text, text, int, text, text, boolean)            TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.enable(text)                                   TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.disable(text)                                  TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.unregister(text)                               TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.get(text)                                      TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.list(boolean)                                  TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.register_action_type(text, text, int, boolean) TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.update_action_type(text, text, int, boolean)   TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.delete_action_type(text)                       TO my_admin_role;
GRANT EXECUTE ON FUNCTION pgrelay.purge(int, int)                                TO my_admin_role;

Step 3 — Register a test channel

SELECT pgrelay.register(
    'hello_world',
    'SELECT pg_catalog.length($1)',
    'A simple test channel');

This registers a channel called hello_world. When the Processor runs it, the action SQL is SELECT pg_catalog.length($1) — a harmless built-in function that just measures the length of the payload text.

Step 4 — Start the Processor

Set the connection environment variables and start it. Use --debug so you can see what it is doing:

export PGHOST=localhost
export PGPORT=5432
export PGDATABASE=your_database
export PGUSER=pgrelay
export PGPASSFILE=/path/to/.pgpass

pg_relay --verbose

You should see:

{"level":"info","msg":"pg_relay started","workers":1,"instance":1}

If you see an error instead, check the message — the most common cause is that the pgrelay role has no login (Step 1) or has no .pgpass entry.

Step 5 — Fire a test event

In another terminal or database session:

SELECT pgrelay.notify('hello_world', 'testing 1 2 3');

Within about one second, the Processor logs:

{"level":"debug","msg":"ok: hello_world, id: 1","instance":1}

Note

The ok message only appears when running with --debug. At --verbose you see lifecycle messages (started, stopped) and warnings. At the default log level (no flag at all) you see only problems.

Step 6 — Check the audit log

SELECT channel, payload, status, elapsed_ms, actioned_at
FROM pgrelay.log
ORDER BY actioned_at DESC
LIMIT 5;

You will see your event with status ok and the time it took to run, in milliseconds.

Step 7 — Grant your action function to pgrelay

When your action calls a function you wrote (which it will, in any real use case), the pgrelay role needs permission to call it:

GRANT EXECUTE ON FUNCTION my_schema.my_function(text) TO pgrelay;

Tip

For more detail on how pg_relay's security model works, and why this grant is necessary, see The Security Model in the Technical Guide.


You now have a fully working pg_relay setup. Continue to Sending Events to learn everything pgrelay.notify() can do, or jump to the Worked Example book for a longer, realistic walkthrough.