We run various automation environments on our German-hosted stack at Hostna, and we frequently encounter configuration hurdles when users transition from a single-process setup to a distributed queue architecture. To fix n8n queue mode when using separate worker processes, you must first ensure that the N8N_ENCRYPTION_KEY is identical across every node and that your Redis instance is configured to listen on a network-accessible IP rather than 127.0.0.1. If the worker starts but does not pick up jobs, or if it throws decryption errors, the issue is almost always a mismatch in environment variables or a firewall blocking the 6379 port.
| Symptom | Primary Cause | Resolution |
|---|---|---|
Worker logs Error: Decryption failed |
N8N_ENCRYPTION_KEY mismatch |
Copy the exact key from the main node .env to the worker node. |
| Worker cannot connect to Redis | Redis bound to localhost only | Change bind 127.0.0.1 to 0.0.0.0 in redis.conf. |
| Jobs stay in ‘Waiting’ state | Worker process not in queue mode |
Ensure worker is started with the worker command, not start. |
| Database connection timeouts | max_connections too low |
Increase PostgreSQL pool limits or database max_connections. |
Synchronizing the Encryption Key for Credential Decryption
The most common failure in a distributed n8n setup is the decryption error. When you create credentials in the n8n UI, they are encrypted using a unique key before being stored in the database. This process uses the Advanced Encryption Standard to protect your API keys and passwords. The N8N_ENCRYPTION_KEY is used by the main process to encrypt sensitive data, and if the worker node uses a different key, it will fail to decrypt credentials, resulting in an execution failure the moment a node attempts to use an external service.
To fix this, you must extract the key from your primary node. If you are using Docker, you can find this in your .env file or by inspecting the running container. Use the following command to verify the key on your main instance:
grep N8N_ENCRYPTION_KEY .env
Once you have this string, you must apply it to every worker process. Without this exact match, the worker is effectively locked out of the data it needs to execute workflows. When dedicated resources for automation are spread across multiple machines, maintaining a single source of truth for environment variables is the most reliable way to prevent these silent failures.
Redis Networking and Binding Configuration
In a standard single-server installation, Redis often runs on 127.0.0.1, which is the loopback address. When you move a worker to a separate virtual machine, that worker will attempt to connect to the Redis host specified in its configuration. If the main server is still only listening on the loopback, the connection will be refused. You must update your Redis configuration to allow external traffic, ideally restricted via a private network or a strict firewall rule.
The BRPOP command in Redis, which n8n uses to fetch jobs from the queue, is a blocking operation that requires a stable network connection with low latency to avoid heartbeat timeouts between the worker and the main process. If your worker is on a different network, check the latency between the nodes. A delay of more than 5 ms can lead to throughput issues. To verify that your worker can actually reach the Redis instance, run this command from the worker node:
redis-cli -h [REDIS_IP_ADDRESS] -p 6379 ping
If you receive a PONG response, the network path is clear. If not, you must check your redis.conf for the bind directive and ensure your firewall allows TCP traffic on port 6379. When deploying on a Linux environment, using ufw or iptables to whitelist only the specific IP addresses of your workers is a vital step in managing your own server security while keeping the queue accessible.
PostgreSQL Database Concurrency and Pooling
Queue mode requires a production-grade database; SQLite is not supported for this configuration. PostgreSQL is the standard choice. Each worker process and the main process will maintain their own connection pool to the database. A PostgreSQL database instance requires its max_connections value to be higher than the sum of the N8N_DB_POSTGRES_POOLSIZE_MAX values across all active worker nodes and the main process.
If you have five workers and each is configured with a maximum pool size of 20, they could theoretically attempt to open 100 connections. If your database max_connections is set to the default of 100, the main process might be unable to connect when the workers are busy. You can check your current connection limit by running this SQL query:
SHOW max_connections;
If the limit is too low, you must adjust it in postgresql.conf and restart the service. For a machine with 4 GB of RAM, a max_connections value of 200 is generally safe, provided the memory overhead of each connection is accounted for in your total resource allocation. When looking at virtual dedicated server options, ensure you have enough memory to handle both the Node.js processes and the database overhead.
Memory Limits and the OOM Killer
Workers are the components that do the heavy lifting. They load the workflow into memory, process the data, and handle the logic. A container with a cgroup memory limit of 2 GB will be terminated by the OOM killer if a workflow processes a large JSON array that exceeds that threshold during a split-in-batches operation. This is especially common when processing high-resolution images or massive CSV files.
The Node.js runtime environment for an n8n worker should be configured with --max-old-space-size=3072 if the underlying virtual machine has 4 GB of physical RAM, ensuring the garbage collector triggers before the cgroup memory limit is reached. Furthermore, setting vm.swappiness to 10 on the worker node ensures the kernel prefers to evict file cache rather than swapping out active worker memory, preventing latency spikes in job execution. You can check your current swappiness value with this command:
cat /proc/sys/vm/swappiness
If the value is high, such as 60, the system may swap out n8n memory even when physical RAM is available, which significantly slows down workflow execution. For more detailed guides on kernel tuning, you can browse our technical documentation library.
Environment Variable Synchronization for Workers
When running separate workers, you must ensure that every environment variable related to the execution is mirrored. This includes not just the encryption key, but also any custom environment variables your workflows rely on, such as NODE_FUNCTION_ALLOW_EXTERNAL or specific binary paths. If a worker lacks a variable that the main process has, the workflow will work during a manual test (which often runs on the main process) but fail when triggered automatically (running on the worker).
The official n8n queue mode documentation specifies that the N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS variable can also cause issues if the worker cannot read the local configuration. Use a shared .env file or a configuration management tool to keep these in sync across your Hostna server and any remote nodes. Consistency is the only way to avoid the ‘works in UI, fails in production’ trap.
Verifying the Worker Heartbeat
If you have configured everything and the workers still appear idle, you need to verify the heartbeat. n8n workers do not register themselves in the database in a way that is visible in the UI; they simply listen to the Redis queue. You can monitor the queue activity in real-time to see if jobs are being claimed. Run this on your Redis server:
redis-cli monitor | grep -i "brpop"
This will show you every time a worker asks Redis for a new job. If you see no activity, the worker is either not pointing at the right Redis host or it is not started in worker mode. Ensure your worker startup command is n8n worker and not the standard n8n start. The start command initiates the web server and UI, which you do not need on a dedicated worker node.
If you have checked the encryption key, the Redis binding, the database connection limits, and the memory settings, but the worker still fails, the last step is to check the Docker logs for specific Node.js errors. Send these logs along with your configuration details if you need to reach out for support; having the specific stack trace from the worker process is the only way to diagnose deeper logic errors in a distributed system.
This article was drafted with AI assistance from Hostna’s own research pipeline and published without individual review. Tell us if anything here is wrong.
