Call queues distribute incoming calls among agents efficiently. This guide covers everything from basic queue setup to advanced ring strategies and real-time monitoring.
An Asterisk call queue holds incoming calls and distributes them to available agents (extensions) using a configurable ring strategy. Callers hear music on hold or periodic announcements while waiting. When an agent becomes available, the next call in the queue is delivered to them.
Queues are essential for:
Support desks handling multiple incoming calls
Sales teams distributing leads fairly
Any scenario where more calls arrive than agents can immediately answer
Configuring queues.conf
Queue configuration lives in /etc/asterisk/queues.conf. Here is a complete support queue example:
/etc/asterisk/queues.conf
[general]
persistentmembers=yes
autofill=yes
shared_lastcall=yes
log_membername_as_agent=yes
[support]
; Ring strategy
strategy=leastrecent
; Timeout for each agent ring attempt (seconds)
timeout=15
; How long to wait before trying the next agent
retry=5
; Which timeout wins when Queue() and queues.conf disagree (see Queue() syntax below)
timeoutpriority=app
; Max callers allowed in queue - 0 for unlimited
maxlen=20
; Wrap-up time after a call (seconds)
wrapuptime=10
; Music on hold class
musicclass=default
; Join announcement
joinempty=yes
leavewhenempty=no
; Announce position in queue
announce-frequency=60
announce-position=yes
announce-holdtime=yes
; Periodic announcements
periodic-announce=queue-thankyou
periodic-announce-frequency=120
; Service level target (seconds)
servicelevel=60
; Ring an in-use agent?
ringinuse=no
; Static members (always in queue)
member => PJSIP/100,0,John Smith,hint:100@default
member => PJSIP/101,0,Jane Doe,hint:101@default
member => PJSIP/102,0,Bob Wilson,hint:102@default
Ring Strategies
The ring strategy determines how calls are distributed among agents. Choose based on your team's workflow:
ringall
Rings all available agents simultaneously. First to answer gets the call. Good for small teams where speed matters.
leastrecent
Rings the agent who has been idle the longest since their last call. Distributes calls evenly over time.
fewestcalls
Rings the agent with the fewest completed calls. Balances total call count across agents.
random
Randomly selects an available agent. Simple and fair over large volumes.
rrmemory
Round-robin with memory. Remembers where it left off and continues to the next agent. Predictable and fair.
linear
Always tries agents in order (first member first). Good when you have a preferred agent or skill-based tiering.
Building this? Your PBX will need a number
Find a phone number for your trunk
Local numbers $1.50 a month, toll-free $2.00, $1.00 one-time setup. Pick one here and it carries into signup.
Enter an area code, or wait a moment for numbers near you.
Penalties, weight, autofill and the two strategies the tiles leave out
Two further strategies are valid in strategy=. wrandom is weighted random: each member's penalty is used as a weight, so a penalty-0 agent is picked more often than a penalty-2 agent but nobody is excluded. rrordered is rrmemory with the member order taken from queues.conf instead of Asterisk's internal order, which is what you want when "ring Alice first, then Bob" has to be predictable.
Penalties are the second field on a member line and work with every strategy except wrandom. Asterisk only rings members with the lowest penalty that is currently available; higher-penalty members are backup agents who ring when nobody with a lower penalty is available:
/etc/asterisk/queues.conf - tiered agents
[support]
strategy=rrordered
timeout=20
retry=2
; penalty 0 = front line, 1 = second line, 2 = managers
member => PJSIP/100,0,Alice,hint:100@default
member => PJSIP/101,0,Bob,hint:101@default
member => PJSIP/110,1,Carol,hint:110@default
member => PJSIP/120,2,Dave,hint:120@default
; include higher-penalty members when fewer than 2 lower-penalty members are available
penaltymemberslimit=2
; escalate automatically the longer the caller waits (rule defined in queuerules.conf)
defaultrule=escalate
/etc/asterisk/queuerules.conf
[escalate]
; after 60 s waiting, also ring penalty 1; after 180 s, also ring penalty 2
penaltychange => 60,1
penaltychange => 180,2
The same thing can be done per call by setting QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY on the channel before Queue(), which is how a VIP caller identified by DID or caller ID can be sent straight to the senior tier.
Two [general] and per-queue options change how those members are used:
autofill=yes delivers several waiting calls to several available agents at the same time. With autofill=no (the pre-1.4 behaviour) the queue hands out one call at a time and the second caller waits until the first has been bridged, even if ten agents are idle.
weight= matters when an agent belongs to more than one queue. If sales has weight=10 and support has weight=0, a shared agent is offered the sales call first whenever both queues have callers waiting.
ringinuse=no skips members whose device state is In Use. Keep it off for ringall queues unless you really want agents on a call to hear a second ring.
Agent Management
Agents can be added to queues statically (in queues.conf) or dynamically (via the dialplan or AMI). Dynamic membership is more flexible for shift-based operations:
extensions.conf - Dynamic agent login/logout
[agents]
; Login to support queue - dial *500
exten => *500,1,NoOp(Agent login to support queue)
same => n,AddQueueMember(support,PJSIP/${CALLERID(num)})
same => n,Playback(agent-loginok)
same => n,Hangup()
; Logout from support queue - dial *501
exten => *501,1,NoOp(Agent logout from support queue)
same => n,RemoveQueueMember(support,PJSIP/${CALLERID(num)})
same => n,Playback(agent-loggedoff)
same => n,Hangup()
; Pause/unpause (toggle) - dial *502
exten => *502,1,NoOp(Toggle agent pause)
same => n,Set(QSTATUS=${QUEUE_MEMBER(support,paused,PJSIP/${CALLERID(num)})})
same => n,GotoIf($["${QSTATUS}"="1"]?unpause)
same => n,PauseQueueMember(support,PJSIP/${CALLERID(num)},,Break)
same => n,Playback(beep)
same => n,Hangup()
same => n(unpause),UnpauseQueueMember(support,PJSIP/${CALLERID(num)})
same => n,Playback(beep&beep)
same => n,Hangup()
Queue Announcements
Keep callers informed while they wait with these announcement options:
announce-frequency: How often (seconds) to announce the caller's position and estimated hold time. Set to 0 to disable.
announce-position: Tell callers their position in queue ("You are caller number 3").
announce-holdtime: Announce estimated hold time based on recent call data. Only announces if the estimate is meaningful.
periodic-announce: Play a custom recording periodically (e.g., "Thank you for holding, your call is important to us").
periodic-announce-frequency: How often (seconds) to play periodic announcements.
Dialplan Integration
Connect incoming calls to your queue through the dialplan. Handle queue exits gracefully:
extensions.conf - Queue with failover
[from-ipcomms]
; Route inbound DID to support queue
exten => 2125551000,1,NoOp(Inbound to support)
same => n,Answer()
same => n,Playback(welcome-message)
same => n,Queue(support,t,,,300)
; If caller times out after 300 seconds (5 min)
same => n,VoiceMail(support@default,u)
same => n,Hangup()
; Alternative: IVR then queue
exten => 2125551001,1,NoOp(Main IVR)
same => n,Answer()
same => n,Background(main-ivr-greeting)
same => n,WaitExten(5)
exten => 1,1,Queue(sales,t,,,180)
same => n,VoiceMail(sales@default,u)
same => n,Hangup()
exten => 2,1,Queue(support,t,,,300)
same => n,VoiceMail(support@default,u)
same => n,Hangup()
The Queue() application options include:
t - Allow the called agent to transfer the call
T - Allow the caller to transfer
n - No retry on timeout (exit queue if no agent answers)
H - Allow the caller to hang up by pressing *
The 5th parameter (300) - Maximum wait time in seconds
Queue() application syntax, options and timeouts
The full signature is Queue(queuename[,options[,URL[,announceoverride[,timeout[,AGI[,gosub[,rule[,position]]]]]]]]). On Asterisk 18 and 20 there is an extra, deprecated macro argument between AGI and gosub; it was removed with the Macro application in Asterisk 21, so count your commas when you copy examples between versions. rule names a section of queuerules.conf for this call only, and position lets you insert a caller ahead of others (1 = front of the queue).
Option
Effect
b(context^exten^priority)
Run a Gosub on the agent's channel before bridging (screen pop, set a variable the agent's phone displays)
B(context^exten^priority)
Run a Gosub on the caller's channel before bridging
C
Mark unanswered ring attempts as "answered elsewhere" so ringall does not leave a missed-call entry on every other agent's phone
c
Continue in the dialplan when the agent hangs up instead of ending the call
d
Data-quality call (minimum delay), for modems and fax
F([context^exten^priority])
When the caller hangs up, send the agent's channel to this location (after-call work, wrap-up codes)
h / H
Agent / caller may hang up by pressing *
i
Ignore call-forward requests from members (a forwarded desk phone no longer steals queue calls)
I
Ignore connected-line and redirecting updates on this attempt
k / K
Agent / caller may park the call with the features.conf parking sequence
n
No retries: after one failed ring attempt leave the queue and continue in the dialplan
r
Play ringing instead of music on hold; periodic announcements still play
R
Music on hold while waiting, ringing only once an agent's phone is actually ringing
t / T
Agent / caller may transfer the call (DTMF transfer from features.conf)
w / W
Agent / caller may start recording with Monitor
x / X
Agent / caller may start recording with MixMonitor
Three timers that are easy to confuse
timeout in queues.conf (default 15): seconds one member's phone rings in a single attempt.
retry in queues.conf (default 5): seconds to wait after a failed attempt before ringing the next member. timeoutrestart=yes restarts the member timer when the attempt ends in BUSY or CONGESTION, so a transient busy does not consume the whole attempt.
Queue() timeout (fifth argument): total seconds the caller may wait. When it expires Queue() returns with QUEUESTATUS=TIMEOUT and the dialplan continues on the next priority. Leaving it empty means the caller waits until an agent answers or the caller hangs up.
timeoutpriority=app (the default) means that when the caller's timeout would expire during a ring attempt, the attempt is cut short and the caller leaves on time. timeoutpriority=conf lets the current member finish ringing first, which is kinder to the agent but can keep the caller up to timeout seconds longer than promised.
Handling how the caller left
QUEUESTATUS is set whenever Queue() returns, so one queue can overflow into another or into voicemail without a second DID:
extensions.conf - routing on QUEUESTATUS
exten => 2125551000,1,NoOp(Inbound to support)
same => n,Answer()
same => n,Queue(support,tC,,,300)
same => n,NoOp(Left support queue: ${QUEUESTATUS})
same => n,GotoIf($["${QUEUESTATUS}"="FULL"]?overflow)
same => n,GotoIf($["${QUEUESTATUS}"="JOINEMPTY"]?closed)
same => n,GotoIf($["${QUEUESTATUS}"="LEAVEEMPTY"]?closed)
same => n,VoiceMail(support@default,u)
same => n,Hangup()
same => n(overflow),Queue(overflow,tC,,,180)
same => n,VoiceMail(support@default,u)
same => n,Hangup()
same => n(closed),Playback(custom/no-agents-logged-in)
same => n,VoiceMail(support@default,u)
same => n,Hangup()
The possible values are TIMEOUT, FULL (maxlen reached), JOINEMPTY (no usable members when the caller arrived), LEAVEEMPTY (the last usable member left while the caller waited), JOINUNAVAIL, LEAVEUNAVAIL and CONTINUE (option c). Which member states count as "empty" is set per queue with joinempty= and leavewhenempty=; current versions take a comma-separated list of states (paused, penalty, inuse, ringing, unavailable, invalid, unknown, wrapup) and still accept the old yes, no, strict and loose keywords. If every agent is logged out, joinempty=paused,invalid,unavailable,unknown sends the caller straight to the closed branch instead of 300 seconds of hold music. The IVR and auto attendant guide shows the menu that normally sits in front of this.
Queue Monitoring and Stats
Monitor queue performance in real-time from the Asterisk CLI:
Asterisk CLI - Queue commands
; Show all queues with stats
queue show
; Show specific queue
queue show support
; Show queue summary (compact view)
queue stats
; Real-time queue log
queue set log on
; Output example:
; support has 2 calls (max 20) in 'leastrecent' strategy
; (service level: 60s)
; Members:
; PJSIP/100 (John Smith) (ringinuse disabled) (Not in use) has taken 15 calls
; PJSIP/101 (Jane Doe) (ringinuse disabled) (In use) has taken 12 calls
; Callers:
; 1. PJSIP/trunk-00000023 (wait: 0:45, prio: 0)
For historical reporting, Asterisk writes queue events to /var/log/asterisk/queue_log. Key events include ENTERQUEUE, CONNECT, ABANDON, COMPLETECALLER, and COMPLETEAGENT. Third-party tools like QueueMetrics can parse these logs into detailed reports.
queue reload, module reload app_queue and when a restart is needed
Nothing in queues.conf needs a restart. Edit the file, then pick the narrowest reload:
Command
What it re-reads
Effect on live calls
queue reload all
queues.conf parameters, static members and queuerules.conf, every queue
None. Waiting callers stay in place; dynamic members are kept
queue reload all support
The same, one queue only
None
queue reload parameters / members / rules
Only that part of the configuration
None
module reload app_queue.so
Equivalent to queue reload all
None
core reload
Every module's configuration, queues included
None, but heavier; avoid during peak hours on busy systems
queue reset stats [queue]
Nothing; zeroes the calls-taken, hold-time and service-level counters
None
core restart gracefully
Restarts Asterisk once the last call ends
Only needed if app_queue was never loaded or you changed the realtime mapping in extconfig.conf
A queue you delete from queues.conf is marked for removal on reload and disappears once its last caller has left. Static members removed from the file are dropped on reload; members that were added with AddQueueMember(), AMI or the CLI survive every reload and, with persistentmembers=yes, every restart as well, because they are stored in the AstDB.
CLI commands for day-to-day agent management
Asterisk CLI - members without touching queues.conf
queue add member PJSIP/103 to support penalty 1 as "Sam Lee" state_interface hint:103@default
queue remove member PJSIP/103 from support
queue pause member PJSIP/103 queue support reason Lunch
queue unpause member PJSIP/103 queue support
queue set penalty 2 on PJSIP/103 in support
queue set ringinuse no on PJSIP/103 in support
queue show support
queue show rules
database show Queue ; persistent dynamic members live here
Everything above is also available through AMI (QueueAdd, QueueRemove, QueuePause, QueueStatus, QueueSummary), which is what wallboards and agent desktops use. Dialplan feature codes like the *500 login example earlier wrap the same functions for agents without a desktop client.
Member status: In use, Not in use, Unavailable and Invalid
The state shown in queue show is the device state of the member's interface, or of its state_interface if one is set. The queue uses it to decide whom to ring, so a wrong state means missed calls or phantom rings.
State
Meaning
Rung by the queue?
Not in use
Registered and idle
Yes
In use / Busy / On Hold
On a call
Only when ringinuse=yes
Ringing / Ring+Inuse
Phone is ringing (possibly from another queue)
No
Unavailable
Interface exists but is unreachable: PJSIP endpoint with no registered contact, phone switched off, qualify failing
No
Invalid
Dial string cannot be resolved: typo, channel driver not loaded, Local channel pointing at a missing extension
No
Unknown
No device state information, typically a Local channel without state_interface
Yes, always, which is the usual cause of agents ringing while they are already on a call
(paused)
Member paused with a reason
No
For PJSIP endpoints the state comes from the registered contact and OPTIONS qualify, so pjsip show contacts and core show hints tell you why a member is Unavailable. The PJSIP configuration guide covers qualify_frequency and max_contacts, the two settings behind most Unavailable states. For members that dial through a Local channel, give the queue the real phone to watch:
/etc/asterisk/queues.conf - Local channel member with a state interface
; member => interface,penalty,membername,state_interface
member => Local/201@from-queue/n,0,Alice,PJSIP/201
From the dialplan or AGI, the QUEUE_MEMBER() function reads the same information: ${QUEUE_MEMBER(support,logged)} counts logged-in members, free counts those not in use, ready those available and not paused, and QUEUE_MEMBER(support,paused,PJSIP/201) or penalty read one member. ${QUEUE_WAITING_COUNT(support)} is the number of callers on hold, useful for an "all agents are busy, leave a message or hold" prompt before Queue().
queue_log: fields, events and computing service level
/var/log/asterisk/queue_log is the source of every queue report. Each line is pipe-separated: epoch|uniqueid|queue|agent|event|param1|param2|param3. The unique ID is the caller's channel unique ID, or NONE, MANAGER and REALTIME for member and system events.
Event
Parameters
Meaning
ENTERQUEUE
url | caller ID
Caller joined the queue
CONNECT
holdtime | bridged channel unique ID | ringtime
Agent answered; holdtime is the caller's wait in seconds
COMPLETECALLER
holdtime | calltime | original position
Call ended, caller hung up first
COMPLETEAGENT
holdtime | calltime | original position
Call ended, agent hung up first
ABANDON
position | original position | waittime
Caller hung up while waiting
EXITWITHTIMEOUT
position | original position | waittime
Queue() timeout expired
EXITEMPTY
position | original position | waittime
Caller left because no members were usable (leavewhenempty)
EXITWITHKEY
key | position | original position | waittime
Caller pressed a key defined in context= to leave
RINGNOANSWER
ringtime (ms)
Member rang and did not answer
TRANSFER
extension | context | holdtime | calltime | original position
Agent transferred the caller
ADDMEMBER / REMOVEMEMBER / PAUSE / UNPAUSE
reason (for PAUSE)
Agent events; PAUSEALL and UNPAUSEALL cover every queue the member is in
CONFIGRELOAD / QUEUESTART
-
Reload and startup markers, handy for explaining gaps in reports
Two one-liners give the numbers most managers ask for. Service level is the share of answered calls whose hold time was within the servicelevel target; abandon rate is abandoned calls over calls offered:
shell - service level and abandon rate for the support queue
For anything beyond that, write the log to a database instead of a flat file: map queue_log => odbc,asterisk in extconfig.conf (with res_config_odbc and a queue_log table), and keep queue_log_to_file=yes in the [general] section of queues.conf if you also want the text file. QueueMetrics, Asternic and most wallboards read exactly these events, so the agent names you set with log_membername_as_agent=yes are what will appear in their reports. The call center SIP trunking guide explains which of these numbers carriers and auditors will ask about.
Recording queue calls
Record at the queue rather than per extension so every answered call is captured regardless of which agent took it. Two options in the queue's section turn it on, and a channel variable set before Queue() controls the file name:
extensions.conf - one file per call, named by time and caller
exten => 2125551000,1,Answer()
same => n,Playback(custom/calls-may-be-recorded)
same => n,Set(MONITOR_FILENAME=/var/spool/asterisk/monitor/support/${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${CALLERID(num)})
same => n,Queue(support,tC,,,300)
monitor-type=MixMonitor records both legs into one file; leaving it unset uses the older Monitor application, which writes two files and mixes them afterwards. wav is safest for playback in a browser; wav49 (GSM inside a WAV container) is about eight times smaller if storage matters. Play a recording notice before the queue: consent rules differ by state and country, and the queue is the one place every caller passes through. Recordings land on the PBX, so size the disk: G.711 at wav is roughly 1 MB per minute per call.
Best Practices
Set ringinuse=no: Prevents delivering queue calls to agents already on a call. Without this, agents on a call will hear another ring.
Use wrapuptime: Give agents 10-30 seconds after each call to complete notes before the next call arrives.
Set a maxlen: Limit the number of callers in queue to prevent extremely long wait times. It is better to send the 21st caller to voicemail than make them wait 30 minutes.
Configure a timeout: Always set a max wait time in the Queue() dialplan application. Send callers to voicemail or a callback option if they wait too long.
Monitor service levels: Track what percentage of calls are answered within your target time (e.g., 80% within 60 seconds). This is the industry-standard metric.
Record queue calls: Use MixMonitor() in the queue member's context to record calls for quality assurance and training.
Asterisk Queue FAQ
How do I set up a call queue in Asterisk?
To set up a call queue in Asterisk, edit /etc/asterisk/queues.conf and define a queue context with parameters like strategy (ringall, leastrecent, round-robin), timeout, retry interval, and member agents. Then reference the queue in your dialplan using the Queue() application. Reload with 'asterisk -rx "module reload app_queue.so"'.
What is periodic-announce in queues.conf?
periodic-announce is a queues.conf parameter that plays a recorded announcement to callers waiting in the queue at regular intervals. Set periodic-announce-frequency (in seconds) to control how often it plays. Common use: 'Your call is important to us, please continue to hold.' You can specify multiple sound files separated by commas.
What ring strategies are available in Asterisk call queues?
Asterisk queues support several ring strategies: ringall (ring all available agents simultaneously), leastrecent (ring agent who has been idle longest), fewestcalls (ring agent with fewest completed calls), random (ring a random agent), rrmemory (round-robin with memory), linear (ring in order listed), and wrandom (weighted random).
How do I reload queues.conf without restarting Asterisk?
Run queue reload all from the Asterisk CLI (or asterisk -rx "queue reload all" from the shell). It re-reads queues.conf and queuerules.conf for every queue, keeps dynamically added members, and does not drop callers who are already waiting or talking. queue reload parameters, queue reload members and queue reload rules reload one part only. module reload app_queue.so does the same as queue reload all. A full core restart is only needed when app_queue was never loaded or you change the realtime configuration in extconfig.conf.
What is the difference between the Queue() timeout and timeout in queues.conf?
timeout in queues.conf is how many seconds one agent's phone rings per attempt (default 15). The fifth argument of Queue() in the dialplan is the total number of seconds the caller may wait before Queue() returns with QUEUESTATUS=TIMEOUT. retry is the pause between attempts. When the two timers would expire at the same moment, timeoutpriority=app (the default) ends the ring attempt immediately in favour of the caller's timeout, while timeoutpriority=conf lets the current ring attempt finish first.
Why does queue show list a member as Invalid or Unavailable?
Invalid means Asterisk cannot resolve the member's dial string: a typo such as PJSIP/1O1, a channel driver that is not loaded, or a Local channel with no matching extension. Unavailable means the interface exists but its device state is unreachable, usually a PJSIP endpoint with no registered contact. Both members are skipped by every strategy. Check with pjsip show contacts and core show hints, and give Local channel members a state_interface so the queue sees the real phone's state.
Where does Asterisk log queue statistics?
Every queue event is appended to /var/log/asterisk/queue_log as pipe-separated fields: epoch, caller unique ID, queue name, agent, event and up to three parameters. ENTERQUEUE, CONNECT, COMPLETECALLER, COMPLETEAGENT, ABANDON and EXITWITHTIMEOUT are enough to compute answered calls, abandon rate, average hold time and service level. queue show gives the live counters since the last reload or queue reset stats; tools such as QueueMetrics or Asternic parse queue_log into reports, and the log can also be written to a database table through extconfig.conf.
What does rrmemory mean in Asterisk?
rrmemory is round-robin with memory. Asterisk rings one member at a time, remembers which member it rang last and starts the next call with the member after that one, so calls rotate evenly instead of always starting from the first agent. rrordered behaves the same but keeps the order in which members are listed in queues.conf rather than the internal order, which makes it the better choice when you want a predictable first-ring agent.
Reliable SIP Trunking for Your Call Center
IPComms provides high-capacity SIP trunks built for call centers: $0 per channel with no set call limits, $0.009/min inbound and $0.010/min outbound, local numbers from $1.50/month and no contracts. Stop worrying about SIP trunk capacity. We have you covered. See our full Asterisk SIP trunking setup guide and the call center solutions page.