PGMQ
Overview
PGMQ is an open-source message queue that runs entirely inside PostgreSQL. It gives you the queue semantics you expect, including visibility timeouts, delivery counting, archiving, and partitioned and unlogged queues. The queue is a set of ordinary Postgres tables and the API is plain SQL, so there is no broker to install, no second service to monitor and no separate cluster to keep alive.
Teams choose PGMQ for transactional integrity. Because the queue lives in the same database as your data, enqueuing a job and writing the row that the job refers to happen in one transaction. Either both commit or neither does. You never publish a message about a row that was rolled back, and you never lose a message that a committed write depended on. This removes a whole category of dual-write bugs that appear when the queue is a separate system.
This SecureAnyCloud image runs PostgreSQL 18 with PGMQ on Ubuntu 24.04 on Azure. PostgreSQL 18 and pg_partman come from the official PostgreSQL PGDG repository. PGMQ 1.12.0 is built from the pinned upstream release with PGXS and is pre-enabled (CREATE EXTENSION pgmq) in a default database named queuedb. That database also ships a small demo_queue that holds two messages, so you can run pgmq.read the moment the VM boots.
No baked-in credential. The postgres superuser role is passwordless by construction. A fresh install leaves it with no password, and the captured image ships that way, so there is no default or blank password to discover. On first boot, each VM generates a unique password for the postgres role and a unique self-signed TLS server certificate. It writes them to the root-only file /root/pgmq-credentials.txt, then enables TLS.
Remote clients are accepted only over TLS (hostssl with scram-sha-256). On-box administration stays passwordless through the local unix socket. Until first boot creates the certificate, the database is not reachable off the box at all.
What you get:
- PostgreSQL 18 from the official PGDG repository, running under systemd as
postgresql.service - PGMQ 1.12.0 pre-enabled in a default database
queuedb, with a seededdemo_queue - pg_partman 5.5.0, which PGMQ requires for partitioned queues, enabled in a dedicated
partmanschema - A built-in self-test at
/usr/local/sbin/pgmq-selftest.shthat proves the whole queue lifecycle over TLS - A per-VM
postgrespassword and a per-VM TLS certificate, generated on first boot and written to a root-only credentials file pg_hba.confconfigured so that remote clients connect only over TLS with the per-VM password, while local access stays passwordless via the unix socket- Unattended security upgrades left enabled, so the appliance keeps receiving patches
Prerequisites
- An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
- A subscription to this listing on Azure Marketplace
- A network security group (NSG) that allows TCP 22 (administration) and TCP 5432 (the PostgreSQL wire protocol) from your client network. In production, restrict
5432to your application subnet.
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development and light workloads. Queue throughput is bound by write throughput, so for busy queues choose a size with faster storage and more RAM, such as Standard_D2s_v5 or larger.
Deploy the virtual machine
Run these commands to create the VM from the image. They open only SSH and the PostgreSQL port.
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:pgmq-ubuntu-24-04:default:latest
az vm create \
--resource-group my-rg \
--name pgmq-1 \
--image sac1647283583153:pgmq-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group my-rg --name pgmq-1 --port 5432 --priority 900Retrieve your per-VM credentials
On first boot, the VM generates its own postgres password and TLS certificate. SSH in and read the root-only credentials file:
sudo cat /root/pgmq-credentials.txtThe file is mode 0600 and owned by root. It contains the per-VM password and a ready-to-paste TLS connection string. Nothing is baked into the image, so every deployed VM has its own password and its own certificate.
Confirm the service is healthy
Run these commands to check that PostgreSQL is active and listening, that TLS is on, and that both extensions are enabled in the default database:
sudo systemctl is-active postgresql.service
sudo ss -tlnp | grep 5432
sudo -u postgres psql -tAc 'SHOW ssl;'
sudo -u postgres psql -d queuedb -c "SELECT extname, extversion FROM pg_extension WHERE extname IN ('pgmq','pg_partman') ORDER BY extname;"The output shows the service active, PostgreSQL listening on 5432, ssl reported as on, and both pgmq at 1.12.0 and pg_partman at 5.5.0.
Send and read your first message
Everything PGMQ does is a SQL function call in the pgmq schema. Create a queue, send JSONB messages, read them back, then archive one:
sudo -u postgres psql -d queuedb <<'SQL' SELECT pgmq.create('orders'); SELECT * FROM pgmq.send('orders', '{"order_id": 1001, "action": "ship"}'); SELECT * FROM pgmq.send('orders', '{"order_id": 1002, "action": "refund"}'); SELECT msg_id, read_ct, message FROM pgmq.read('orders', 30, 2); SELECT pgmq.archive('orders', 1); SELECT msg_id, message FROM pgmq.a_orders; SELECT queue_name, queue_length, total_messages FROM pgmq.metrics('orders'); SELECT pgmq.drop_queue('orders'); SQLpgmq.send returns the msg_id of each message. pgmq.read('orders', 30, 2) takes up to two messages and hides them from every other consumer for 30 seconds. This visibility timeout stops two workers from processing the same job.
Each returned row carries read_ct, the number of delivery attempts. Use it to spot a poison message that keeps failing.
pgmq.archive moves a message out of the queue table pgmq.q_orders and into the archive table pgmq.a_orders, so you keep an auditable history instead of deleting it. Use pgmq.delete instead if you do not want to retain the message.
If a worker crashes before it archives a message, the visibility timeout expires and the message becomes visible again for another worker to pick up. Nothing is lost.
Verify the appliance with the built-in self-test
Every image ships a self-test. It connects over TLS with this VM's own credentials, exercises the complete queue lifecycle, and then proves that a wrong password is rejected:
sudo /usr/local/sbin/pgmq-selftest.shIt exits 0 only if every step held. Run it after deployment, after a restore, or any time you want fast end-to-end proof that the appliance is healthy.
Connect from a remote client
On the VM itself, connect as the postgres superuser through the local unix socket. No password is needed:
sudo -u postgres psql -d queuedb -c "SELECT version();"From a remote client, connect over TLS with the per-VM password from the credentials file. Replace <vm-ip> with your VM's address and <POSTGRES_PASSWORD> with the value from the file:
PGPASSWORD=<POSTGRES_PASSWORD> psql "host=<vm-ip> port=5432 dbname=queuedb user=postgres sslmode=require" -c "SELECT ssl, version AS tls FROM pg_stat_ssl WHERE pid = pg_backend_pid();"The pg_stat_ssl view confirms that the connection is encrypted (ssl is t) and reports the negotiated TLS version.
Any PostgreSQL driver works unchanged, because PGMQ is only SQL. Your application calls pgmq.send and pgmq.read the same way it runs any other query, inside your existing transactions.
Queue types and maintenance
pgmq.create makes a standard durable queue. Two other shapes are available:
sudo -u postgres psql -d queuedb <<'SQL' SELECT pgmq.create_unlogged('fast_queue'); SELECT pgmq.create_partitioned('events_queue'); SELECT queue_name, is_partitioned, is_unlogged FROM pgmq.meta ORDER BY queue_name; SELECT pgmq.drop_queue('fast_queue'); SELECT pgmq.drop_queue('events_queue'); SQLUnlogged queues skip the write-ahead log for much higher throughput. The cost is that they lose their contents if the server crashes, so use them for work that is cheap to regenerate.
Partitioned queues spread a queue across time or id ranges through pg_partman. This makes retention and the pruning of old messages far cheaper on very high-volume queues. pg_partman is installed and enabled in this image for exactly this reason, so pgmq.create_partitioned works out of the box.
pgmq.meta lists every queue on the appliance and which shape it is. For partitioned queues, run partition maintenance on your own schedule by calling partman.run_maintenance_proc(). The pg_partman background worker is deliberately not preloaded, so you control when maintenance runs.
Security posture
No baked-in credential. The postgres role ships passwordless. The per-VM password is generated only on first boot and stored in /root/pgmq-credentials.txt (mode 0600, root only). No other login role exists in the image.
TLS for every remote connection. pg_hba.conf permits remote clients only via hostssl ... scram-sha-256. Each VM creates its own self-signed certificate on first boot, so no certificate is shared between deployments.
Passwordless local access. On-box administration uses the unix socket (sudo -u postgres psql) without a password.
No build toolchain. PGMQ is compiled at build time and the PGXS toolchain is then removed, so the image carries no development packages it does not need.
Network. Expose only TCP 22 and TCP 5432 in your NSG, and restrict 5432 to your application subnet. The NSG is the first layer. TLS and the per-VM password are the second.
To rotate the password later, run sudo -u postgres psql -c "ALTER ROLE postgres PASSWORD '<new>'" and update the credentials file to match.
Operations
Manage the service through systemd and inspect logs with journalctl:
sudo systemctl status postgresql.service --no-pager sudo journalctl -u postgresql@18-main.service --no-pager | tail -20Take a logical backup of a database with pg_dump, for example sudo -u postgres pg_dump queuedb > queuedb.sql. Queues are ordinary tables, so a normal Postgres backup captures your queue state and its archive along with the rest of your data. Any PostgreSQL monitoring or replication you already run covers the queue too.
The data directory lives under /var/lib/postgresql/18/main.
Support
Every SecureAnyCloud image includes 24/7 support. For questions about this PostgreSQL with PGMQ image, contact us at sales@secureanycloud.com.
Deploy on Azure
Launch PostgreSQL 18 with PGMQ on Ubuntu 24.04 on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com