{"slug":"route-injection","title":"Route injection","tags":["tailscale","routing"],"agent_summary":"Last validated: Feb 13, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Route injection\r\n\r\nLast validated: Feb 13, 2026\r\n\r\nWhen you set up [subnet routers](https://tailscale.com/docs/features/subnet-routers), [exit nodes](https://tailscale.com/docs/features/exit-nodes), or [app connectors](https://tailscale.com/docs/features/app-connectors), Tailscale injects routes into client routing tables so traffic reaches the correct destination. This topic explains the complete route injection process, including when routes appear in client routing tables, how access controls interact with routing, and how router selection works.\r\n\r\n## [Route injection and access controls](https://tailscale.com/docs/reference/route-injection\\#route-injection-and-access-controls)\r\n\r\nRoutes and access controls operate at different layers and serve different purposes:\r\n\r\n- **Routes** (Layer 3): Determine which IP ranges are reachable through the Tailscale tunnel\r\n- **Access controls (ACLs/grants)**: Determine which connections are permitted over the Tailscale network\r\n\r\nA common misconception is that [grants](https://tailscale.com/docs/features/access-control/grants) or [ACLs](https://tailscale.com/docs/features/access-control/acls) control route injection. They do not. Grants control packet filtering, while routes are injected based on what subnet routers advertise and what the control plane approves.\r\n\r\nFor traffic to flow successfully, you need both:\r\n\r\n1. A route to direct packets into the tunnel\r\n2. An access control rule to permit the packets\r\n\r\nYou can have a route without ACL access (packets enter the tunnel but are dropped by the filter), or ACL access without a route (packets never enter the tunnel). Both conditions must be satisfied for end-to-end connectivity.\r\n\r\n## [When routes are injected](https://tailscale.com/docs/reference/route-injection\\#when-routes-are-injected)\r\n\r\nRoutes are injected into a client's routing table when all following conditions are met:\r\n\r\n1. **A subnet router advertises the route**. The subnet router uses `--advertise-routes` to announce which subnets it can reach.\r\n\r\n2. **An admin approves the route**. Routes must be approved in the [admin console](https://tailscale.com/docs/features/subnet-routers#enable-subnet-routes-from-the-admin-console) or through [`autoApprovers`](https://tailscale.com/docs/reference/syntax/policy-file#autoapprovers) in the tailnet policy file.\r\n\r\n3. **The control plane distributes the route**. After approval, the control plane includes the route in the network map sent to clients.\r\n\r\n4. **The client accepts subnet routes**. The client must have route acceptance enabled:\r\n   - Windows, macOS, Android, iOS, and tvOS accept routes by default\r\n   - Linux requires [`tailscale set --accept-routes`](https://tailscale.com/docs/reference/tailscale-cli#set)\r\n\r\nRoutes appear because clients receive them in the network map after they're advertised and approved; clients don't probe a router with pings before installing routes.\r\n\r\nIf a router is offline or access controls don't permit traffic to flow, the route may still be present but traffic won't successfully traverse it.\r\n\r\n## [How routes and ACLs interact with CIDR ranges](https://tailscale.com/docs/reference/route-injection\\#how-routes-and-acls-interact-with-cidr-ranges)\r\n\r\nA common question is whether a grant allowing a CIDR range (like `0.0.0.0/0`) causes all advertised routes within that range to be injected. The answer is no. Grants and routes are evaluated independently:\r\n\r\n- **Route injection**: The client receives exactly the routes that subnet routers advertise and admins approve. If a router advertises `10.1.0.0/24`, clients get a route to `10.1.0.0/24`. A grant allowing `10.0.0.0/8` does not cause additional routes to be injected.\r\n\r\n- **ACL evaluation**: When traffic flows through an injected route, the packet filter checks if a grant permits that specific traffic. A grant allowing `10.0.0.0/8` permits traffic to any IP within that range, regardless of how many or how few routes exist within it.\r\n\r\n\r\n### [Route prefix matching for failover](https://tailscale.com/docs/reference/route-injection\\#route-prefix-matching-for-failover)\r\n\r\nWhen multiple subnet routers advertise routes, only _exact_ prefix matches are grouped for [high availability](https://tailscale.com/docs/how-to/set-up-high-availability). For example:\r\n\r\n- Two routers advertising `10.0.0.0/24` are failover candidates for each other\r\n- One router advertising `10.0.0.0/24` and another advertising `10.0.0.0/16` are _not_ failover candidates, even though the `/16` contains the `/24`\r\n\r\nThe operating system's routing table handles longest-prefix matching as usual. If routes exist to both `10.0.0.0/8` and `10.1.0.0/16`, traffic to `10.1.0.5` uses the more specific `/16` route.\r\n\r\n## [Choosing a router (when multiple routers advertise the same route)](https://tailscale.com/docs/reference/route-injection\\#choosing-a-router-when-multiple-routers-advertise-the-same-route)\r\n\r\nWhen multiple subnet routers advertise the same route, the control plane distributes the available routers in the network map and clients choose an active route based on availability and preferences (for example, high-availability or regional routing settings).\r\n\r\nThe choice depends on factors such as:\r\n\r\n- **Availability**: The router must be connected to the control plane with a valid, unexpired key.\r\n- **High availability**: If you configure multiple routers for the same prefix, clients can fail over when the active router becomes unavailable.\r\n- **Regional routing**: If [regional routing](https://tailscale.com/docs/how-to/set-up-high-availability) is enabled, clients prefer a router in their closest DERP region based on latency measurements.\r\n\r\n### [Accessible routers for `via` routing](https://tailscale.com/docs/reference/route-injection\\#accessible-routers-for-via-routing)\r\n\r\nWhen using the [`via` field](https://tailscale.com/docs/features/access-control/grants/grants-via) in grants to specify which routers can handle traffic, only \"accessible\" routers are candidates. A router is accessible when:\r\n\r\n- The router is connected to the control plane\r\n- The router's key has not expired\r\n- Access control rules permit the user to reach the router\r\n\r\n`via` routing is policy-aware: a router must be eligible for the user and traffic in question, and tailnet policy can limit which routers may be used.\r\n\r\nIf policy prevents a user from using a router, that router won't be a usable `via` candidate for that user.\r\n\r\n## [Interaction between routes and grants](https://tailscale.com/docs/reference/route-injection\\#interaction-between-routes-and-grants)\r\n\r\nConsider this example grant:\r\n\r\n```json\r\n{\r\n  \"grants\": [\\\r\n    {\\\r\n      \"src\": [\"group:engineering\"],\\\r\n      \"dst\": [\"192.168.0.0/16\"],\\\r\n      \"ip\": [\"*\"]\\\r\n    }\\\r\n  ]\r\n}\r\n```\r\n\r\nThis grant permits `group:engineering` to send traffic to `192.168.0.0/16`. However, the grant does not inject any routes. For traffic to actually reach `192.168.0.0/16`:\r\n\r\n1. A subnet router must advertise a route covering that range\r\n2. The route must be approved\r\n3. Each client must accept routes\r\n\r\nIf a subnet router advertises `192.168.1.0/24`, clients receive that specific route. Traffic to `192.168.1.50` works (route exists, ACL permits). Traffic to `192.168.2.50` fails because no route covers it, even though the grant would permit the traffic.\r\n\r\nConversely, if a subnet router advertises `10.0.0.0/8` but no grant covers it, clients receive the route but traffic is dropped by the packet filter.\r\n\r\n## [Troubleshooting](https://tailscale.com/docs/reference/route-injection\\#troubleshooting)\r\n\r\n### [Routes not appearing on client](https://tailscale.com/docs/reference/route-injection\\#routes-not-appearing-on-client)\r\n\r\nIf expected routes don't appear on a client:\r\n\r\n1. Verify the subnet router is advertising the routes in the admin console or with `tailscale status --json` on the router.\r\n2. Confirm the routes are approved in the admin console.\r\n3. On Linux, verify route acceptance is enabled. Run `tailscale debug prefs` and check if `RouteAll` is `true`. If `false`, run `tailscale set --accept-routes`.\r\n4. Check if a more specific local route takes precedence using your OS routing table commands (`ip route` on Linux, `netstat -rn` on macOS).\r\n\r\n### [Traffic blocked despite route existing](https://tailscale.com/docs/reference/route-injection\\#traffic-blocked-despite-route-existing)\r\n\r\nIf routes exist but traffic is blocked:\r\n\r\n1. Verify an ACL or grant permits the traffic. Run `tailscale debug netmap` and examine the `PacketFilter` section to check effective rules.\r\n2. Confirm the destination is reachable from the subnet router itself.\r\n3. Check if firewalls on the subnet router or destination are blocking traffic.\r\n\r\n### [Failover not working](https://tailscale.com/docs/reference/route-injection\\#failover-not-working)\r\n\r\nIf failover between subnet routers isn't working:\r\n\r\n1. Verify both routers advertise exactly the same routes (same CIDR prefixes).\r\n2. Confirm both routes are approved in the admin console.\r\n3. Check that both routers are connected and have valid keys.\r\n\r\n![Project Logo](https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed)\r\n\r\nAsk AI\r\n\r\nreCAPTCHA\r\n\r\nRecaptcha requires verification.\r\n\r\nprotected by **reCAPTCHA**\r\n","html":"<h1>Route injection</h1>\n<p>Last validated: Feb 13, 2026</p>\n<p>When you set up <a href=\"https://tailscale.com/docs/features/subnet-routers\">subnet routers</a>, <a href=\"https://tailscale.com/docs/features/exit-nodes\">exit nodes</a>, or <a href=\"https://tailscale.com/docs/features/app-connectors\">app connectors</a>, Tailscale injects routes into client routing tables so traffic reaches the correct destination. This topic explains the complete route injection process, including when routes appear in client routing tables, how access controls interact with routing, and how router selection works.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/route-injection#route-injection-and-access-controls\">Route injection and access controls</a></h2>\n<p>Routes and access controls operate at different layers and serve different purposes:</p>\n<ul>\n<li><strong>Routes</strong> (Layer 3): Determine which IP ranges are reachable through the Tailscale tunnel</li>\n<li><strong>Access controls (ACLs/grants)</strong>: Determine which connections are permitted over the Tailscale network</li>\n</ul>\n<p>A common misconception is that <a href=\"https://tailscale.com/docs/features/access-control/grants\">grants</a> or <a href=\"https://tailscale.com/docs/features/access-control/acls\">ACLs</a> control route injection. They do not. Grants control packet filtering, while routes are injected based on what subnet routers advertise and what the control plane approves.</p>\n<p>For traffic to flow successfully, you need both:</p>\n<ol>\n<li>A route to direct packets into the tunnel</li>\n<li>An access control rule to permit the packets</li>\n</ol>\n<p>You can have a route without ACL access (packets enter the tunnel but are dropped by the filter), or ACL access without a route (packets never enter the tunnel). Both conditions must be satisfied for end-to-end connectivity.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/route-injection#when-routes-are-injected\">When routes are injected</a></h2>\n<p>Routes are injected into a client's routing table when all following conditions are met:</p>\n<ol>\n<li>\n<p><strong>A subnet router advertises the route</strong>. The subnet router uses <code>--advertise-routes</code> to announce which subnets it can reach.</p>\n</li>\n<li>\n<p><strong>An admin approves the route</strong>. Routes must be approved in the <a href=\"https://tailscale.com/docs/features/subnet-routers#enable-subnet-routes-from-the-admin-console\">admin console</a> or through <a href=\"https://tailscale.com/docs/reference/syntax/policy-file#autoapprovers\"><code>autoApprovers</code></a> in the tailnet policy file.</p>\n</li>\n<li>\n<p><strong>The control plane distributes the route</strong>. After approval, the control plane includes the route in the network map sent to clients.</p>\n</li>\n<li>\n<p><strong>The client accepts subnet routes</strong>. The client must have route acceptance enabled:</p>\n<ul>\n<li>Windows, macOS, Android, iOS, and tvOS accept routes by default</li>\n<li>Linux requires <a href=\"https://tailscale.com/docs/reference/tailscale-cli#set\"><code>tailscale set --accept-routes</code></a></li>\n</ul>\n</li>\n</ol>\n<p>Routes appear because clients receive them in the network map after they're advertised and approved; clients don't probe a router with pings before installing routes.</p>\n<p>If a router is offline or access controls don't permit traffic to flow, the route may still be present but traffic won't successfully traverse it.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/route-injection#how-routes-and-acls-interact-with-cidr-ranges\">How routes and ACLs interact with CIDR ranges</a></h2>\n<p>A common question is whether a grant allowing a CIDR range (like <code>0.0.0.0/0</code>) causes all advertised routes within that range to be injected. The answer is no. Grants and routes are evaluated independently:</p>\n<ul>\n<li>\n<p><strong>Route injection</strong>: The client receives exactly the routes that subnet routers advertise and admins approve. If a router advertises <code>10.1.0.0/24</code>, clients get a route to <code>10.1.0.0/24</code>. A grant allowing <code>10.0.0.0/8</code> does not cause additional routes to be injected.</p>\n</li>\n<li>\n<p><strong>ACL evaluation</strong>: When traffic flows through an injected route, the packet filter checks if a grant permits that specific traffic. A grant allowing <code>10.0.0.0/8</code> permits traffic to any IP within that range, regardless of how many or how few routes exist within it.</p>\n</li>\n</ul>\n<h3><a href=\"https://tailscale.com/docs/reference/route-injection#route-prefix-matching-for-failover\">Route prefix matching for failover</a></h3>\n<p>When multiple subnet routers advertise routes, only <em>exact</em> prefix matches are grouped for <a href=\"https://tailscale.com/docs/how-to/set-up-high-availability\">high availability</a>. For example:</p>\n<ul>\n<li>Two routers advertising <code>10.0.0.0/24</code> are failover candidates for each other</li>\n<li>One router advertising <code>10.0.0.0/24</code> and another advertising <code>10.0.0.0/16</code> are <em>not</em> failover candidates, even though the <code>/16</code> contains the <code>/24</code></li>\n</ul>\n<p>The operating system's routing table handles longest-prefix matching as usual. If routes exist to both <code>10.0.0.0/8</code> and <code>10.1.0.0/16</code>, traffic to <code>10.1.0.5</code> uses the more specific <code>/16</code> route.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/route-injection#choosing-a-router-when-multiple-routers-advertise-the-same-route\">Choosing a router (when multiple routers advertise the same route)</a></h2>\n<p>When multiple subnet routers advertise the same route, the control plane distributes the available routers in the network map and clients choose an active route based on availability and preferences (for example, high-availability or regional routing settings).</p>\n<p>The choice depends on factors such as:</p>\n<ul>\n<li><strong>Availability</strong>: The router must be connected to the control plane with a valid, unexpired key.</li>\n<li><strong>High availability</strong>: If you configure multiple routers for the same prefix, clients can fail over when the active router becomes unavailable.</li>\n<li><strong>Regional routing</strong>: If <a href=\"https://tailscale.com/docs/how-to/set-up-high-availability\">regional routing</a> is enabled, clients prefer a router in their closest DERP region based on latency measurements.</li>\n</ul>\n<h3><a href=\"https://tailscale.com/docs/reference/route-injection#accessible-routers-for-via-routing\">Accessible routers for <code>via</code> routing</a></h3>\n<p>When using the <a href=\"https://tailscale.com/docs/features/access-control/grants/grants-via\"><code>via</code> field</a> in grants to specify which routers can handle traffic, only \"accessible\" routers are candidates. A router is accessible when:</p>\n<ul>\n<li>The router is connected to the control plane</li>\n<li>The router's key has not expired</li>\n<li>Access control rules permit the user to reach the router</li>\n</ul>\n<p><code>via</code> routing is policy-aware: a router must be eligible for the user and traffic in question, and tailnet policy can limit which routers may be used.</p>\n<p>If policy prevents a user from using a router, that router won't be a usable <code>via</code> candidate for that user.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/route-injection#interaction-between-routes-and-grants\">Interaction between routes and grants</a></h2>\n<p>Consider this example grant:</p>\n<pre><code class=\"language-json\">{\r\n  \"grants\": [\\\r\n    {\\\r\n      \"src\": [\"group:engineering\"],\\\r\n      \"dst\": [\"192.168.0.0/16\"],\\\r\n      \"ip\": [\"*\"]\\\r\n    }\\\r\n  ]\r\n}\n</code></pre>\n<p>This grant permits <code>group:engineering</code> to send traffic to <code>192.168.0.0/16</code>. However, the grant does not inject any routes. For traffic to actually reach <code>192.168.0.0/16</code>:</p>\n<ol>\n<li>A subnet router must advertise a route covering that range</li>\n<li>The route must be approved</li>\n<li>Each client must accept routes</li>\n</ol>\n<p>If a subnet router advertises <code>192.168.1.0/24</code>, clients receive that specific route. Traffic to <code>192.168.1.50</code> works (route exists, ACL permits). Traffic to <code>192.168.2.50</code> fails because no route covers it, even though the grant would permit the traffic.</p>\n<p>Conversely, if a subnet router advertises <code>10.0.0.0/8</code> but no grant covers it, clients receive the route but traffic is dropped by the packet filter.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/route-injection#troubleshooting\">Troubleshooting</a></h2>\n<h3><a href=\"https://tailscale.com/docs/reference/route-injection#routes-not-appearing-on-client\">Routes not appearing on client</a></h3>\n<p>If expected routes don't appear on a client:</p>\n<ol>\n<li>Verify the subnet router is advertising the routes in the admin console or with <code>tailscale status --json</code> on the router.</li>\n<li>Confirm the routes are approved in the admin console.</li>\n<li>On Linux, verify route acceptance is enabled. Run <code>tailscale debug prefs</code> and check if <code>RouteAll</code> is <code>true</code>. If <code>false</code>, run <code>tailscale set --accept-routes</code>.</li>\n<li>Check if a more specific local route takes precedence using your OS routing table commands (<code>ip route</code> on Linux, <code>netstat -rn</code> on macOS).</li>\n</ol>\n<h3><a href=\"https://tailscale.com/docs/reference/route-injection#traffic-blocked-despite-route-existing\">Traffic blocked despite route existing</a></h3>\n<p>If routes exist but traffic is blocked:</p>\n<ol>\n<li>Verify an ACL or grant permits the traffic. Run <code>tailscale debug netmap</code> and examine the <code>PacketFilter</code> section to check effective rules.</li>\n<li>Confirm the destination is reachable from the subnet router itself.</li>\n<li>Check if firewalls on the subnet router or destination are blocking traffic.</li>\n</ol>\n<h3><a href=\"https://tailscale.com/docs/reference/route-injection#failover-not-working\">Failover not working</a></h3>\n<p>If failover between subnet routers isn't working:</p>\n<ol>\n<li>Verify both routers advertise exactly the same routes (same CIDR prefixes).</li>\n<li>Confirm both routes are approved in the admin console.</li>\n<li>Check that both routers are connected and have valid keys.</li>\n</ol>\n<p><img src=\"https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed\" alt=\"Project Logo\"></p>\n<p>Ask AI</p>\n<p>reCAPTCHA</p>\n<p>Recaptcha requires verification.</p>\n<p>protected by <strong>reCAPTCHA</strong></p>\n"}