VoIP.info Diagnostic

FreePBX PJSIP registration exceeds max contacts or replaces a device

Compare FreePBX extension intent, generated AoR policy, loaded contacts and REGISTER source changes before raising max contacts or enabling automatic replacement.

Reviewed 2026-10-12Current Asterisk res_pjsip and diagnostic references plus Sangoma FreePBX extension semantics and Core GraphQL fields reviewed October 6, 2026; the Sangoma Extensions page says it was updated for FreePBX 13, so the installed FreePBX 17 interface and generated configuration remain authoritativeAdvancedDocumentation based · not lab tested

Classify the observed failure

Record the exact symptom: a REGISTER rejection, an older device losing its binding, one device replacing another, several contacts accumulating, a contact flapping between addresses or only one of several registered devices ringing. These outcomes involve different boundaries. max_contacts governs admitted dynamic bindings; it does not promise that all contacts ring or that a particular device wins replacement.

Capture the extension, endpoint and AoR names without exposing secrets. Note the event time, response code, Contact URI, expiration, received source address and whether the previously bound device changed state. Do not infer a licensing, concurrency or line-key limit from a contact-count message.

Compare four layers before changing FreePBX

Preserve four distinct layers: the extension settings intended in the supported FreePBX interface, the generated PJSIP configuration, the endpoint and AoR objects loaded by Asterisk, and the live contacts produced by REGISTER. Sangoma's current Core GraphQL API exposes a maxContacts extension field, but an API or GUI value is still intent until configuration is applied and loaded.

Use pjsip show endpoint <name> to confirm the associated AoR and pjsip show aor <name> to inspect the loaded contact policy and contact URIs. If these do not match the managed setting, keep the correction in generation, apply-config or reload handling rather than editing generated files directly.

Explain every live contact

For each contact, record its URI, user, address and port, transport, expiration, status and round-trip value when qualification is enabled. Compare those values with authorized phones, softphones or gateways. A duplicate-looking URI may be a refreshed NAT mapping; distinct URIs may be intentional devices sharing one extension.

If rewrite_contact is enabled, compare the REGISTER Contact header with the received source address. A changed translated port can create a new stored contact before an older binding expires. Do not label it a second device without stronger identity evidence, and do not delete contacts merely because their address differs from a provisioning record.

Inspect eviction policy and qualification evidence

Read the loaded values of max_contacts, remove_existing, remove_unavailable, qualify_frequency, qualify_timeout and related qualification options. When replacement is allowed, Asterisk may remove the soonest-expiring contacts to get under the maximum. When unavailable-contact removal is used, its decision relies on qualification state and its interaction with replacement behavior.

A contact shown as Reachable or Unreachable reflects an OPTIONS observation; Unqualified or Unknown may mean the evidence needed for automatic cleanup is absent. Do not enable qualification or eviction globally as a guess. Establish the intended device count, NAT behavior and failure policy for this extension first.

Separate admission from ringing behavior

If all expected contacts are admitted but only one rings, inspect the dial string rather than raising max_contacts. Asterisk documents that Dial(PJSIP/endpoint) uses the first contact, while PJSIP_DIAL_CONTACTS() constructs a destination list for all contacts. FreePBX may generate its own managed dialplan, so capture the actual branch and outbound channels on a new authorized call.

Do not replace managed FreePBX dialplan with a hand-edited shortcut. Confirm whether the requirement is one primary device, simultaneous endpoints, Follow Me, a ring group or another managed feature, then use the supported owner for that behavior.

Correct one owner and retest the lifecycle

Correct only the demonstrated owner: approved device allocation, extension contact limit, replacement policy, qualification policy, NAT or transport behavior, generated configuration, apply-config state or dial behavior. Apply through the supported FreePBX interface or API, then confirm the newly loaded AoR rather than treating a successful save as acceptance.

Retest initial registration, refresh from the same address, refresh after an authorized NAT rebinding, a second approved device, an excess device, expiry, unavailable-contact handling and the intended call-routing behavior. Record each REGISTER result, resulting contact set and outbound channel separately. No FreePBX or Asterisk host, module, endpoint, AoR, contact, device, registration, NAT binding, qualification exchange, dial string, call, media path, availability, compatibility or price was inspected or tested for this diagnostic.

Verify the resulting dial set after contact-policy changes

After correcting contact limits or replacement policy, use the Asterisk multi-contact diagnostic to prove the intended contacts enter the generated dial string.

Sources & applicability

Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.

Examples require adaptation to your topology. No live PBX or hardware testing is claimed.