Type something to search...
How to fix DNS conflicts between CNAME and other records?

How to fix DNS conflicts between CNAME and other records?

To fix a DNS conflict between a CNAME and other records, you need to make sure the name that holds the CNAME has no other records at all. Either delete the other records (A, AAAA, MX, TXT and so on) from that name and keep the CNAME, or delete the CNAME and replace it with the records the target would have given you. At the root of your domain, where SOA and NS records must exist, a CNAME is never allowed, so use your provider's ALIAS, ANAME or CNAME flattening feature, or plain A and AAAA records, instead.

This rule catches people out constantly, usually when a SaaS provider asks for a CNAME on a name that already has a TXT verification record, or when someone tries to point the bare domain at a hosting platform. In this article you'll learn exactly what the rule says and why it exists, the error messages you'll see from different tools, how to find conflicts in an existing zone, and a set of practical fixes for each of the common scenarios.

The Rule: A CNAME Must Stand Alone

A CNAME (canonical name) record says "this name is an alias for another name". When a resolver finds a CNAME, it stops looking at the original name and restarts the lookup at the target. That's the whole point of the record, and it's also why it can't sit alongside anything else.

The original DNS specification, RFC 1034, says that if a CNAME is present at a node, no other data should be present. RFC 2181 later clarified this: a name with a CNAME can't have any other record types, apart from the DNSSEC records that sign it (RRSIG and NSEC or NSEC3). There can also only be one CNAME at a given name.

Why the Rule Exists

Imagine a zone that contains both of these:

www.example.com.  3600  IN  CNAME  example.netlify.app.
www.example.com.  3600  IN  TXT    "site-verification=abc123"

When a resolver asks for the TXT record of www.example.com, what should it return? The CNAME says "everything about this name lives at example.netlify.app", so the correct answer would be the TXT records of the target. But the zone also has a TXT record locally. The two pieces of data contradict each other, and different servers would resolve the contradiction in different ways. The specification avoids the ambiguity by forbidding the combination entirely.

Which Records Commonly Collide

In practice, the conflicts you'll run into are nearly always one of these:

Existing record at the nameWhat you're trying to addTypical cause
SOA and NS (the zone apex)CNAMEPointing the bare domain at a platform such as a static host or load balancer
A or AAAACNAMEMoving a subdomain from a server IP to a SaaS hostname without deleting the old A record
TXTCNAMEA domain verification or SPF record already lives on the subdomain
MXCNAMEA subdomain that receives email is being pointed at a web host
CNAMECNAMETwo services both want the same subdomain
CNAMETXT, MX or AA provider asks for a TXT record on a name that's already an alias

How to Recognise a CNAME Conflict

Most DNS dashboards refuse to save a conflicting record, and the wording of the error usually gives it away. You'll see messages along the lines of "a CNAME record already exists with this name", "CNAME records cannot coexist with other records", or "a record with that host already exists".

If you edit zone files directly, BIND's checker reports the problem clearly:

named-checkzone example.com /etc/bind/zones/db.example.com
dns_master_load: /etc/bind/zones/db.example.com:14: www.example.com: CNAME and other data
zone example.com/IN: loading from master file /etc/bind/zones/db.example.com failed: CNAME and other data
zone example.com/IN: not loaded due to errors.

BIND refuses to load the whole zone in that case, which is a good reason to always run named-checkzone before reloading.

When the Conflict Slips Through

Some systems don't stop you. Older control panels, some hosting panels that manage DNS for you, and hand-written zones loaded into less strict servers may accept the bad data. The symptoms are then much less obvious:

  • A verification check keeps failing even though you can see the TXT record in your dashboard.
  • Email for a subdomain stops arriving after someone added a CNAME for the web host.
  • Different resolvers return different answers for the same name.
  • A certificate authority can't validate a domain because its lookup follows the CNAME and never sees your local record.

You can confirm what the world actually sees with dig. Query the type that seems to be missing and look at the answer section:

dig www.example.com TXT +noall +answer
www.example.com.        300     IN      CNAME   example.netlify.app.

If the answer contains a CNAME and nothing else, the resolver followed the alias and found no TXT record at the target. Your local TXT record is effectively invisible.

How to Find Conflicts in an Existing Zone

If you've inherited a large zone or you're auditing before a migration, it's worth scanning for conflicts rather than waiting for something to break.

Using a Zone File Export

Most providers let you export the zone in BIND format. Once you have the file, a short script can list every name that has a CNAME plus anything else:

#!/usr/bin/env python3
"""List names in a zone export that have a CNAME plus other records.

Expects one record per line with fully qualified names, which is how most
provider exports look: name TTL class type data
"""
import sys
from collections import defaultdict

ALLOWED_WITH_CNAME = {"CNAME", "RRSIG", "NSEC", "NSEC3"}
CLASSES = {"IN", "CH", "HS"}

types_by_name = defaultdict(set)

with open(sys.argv[1]) as f:
    for line in f:
        line = line.split(";", 1)[0].strip()
        if not line or line.startswith("$"):
            continue
        fields = line.split()
        name = fields[0].lower()
        # Skip the optional TTL and class to find the record type
        rest = [x for x in fields[1:4] if not x.isdigit() and x.upper() not in CLASSES]
        if rest:
            types_by_name[name].add(rest[0].upper())

found = False
for name, types in sorted(types_by_name.items()):
    if "CNAME" in types and types - ALLOWED_WITH_CNAME:
        found = True
        others = ", ".join(sorted(types - ALLOWED_WITH_CNAME))
        print(f"{name}: CNAME conflicts with {others}")

if not found:
    print("No CNAME conflicts found.")

Run it against your export:

python3 find_cname_conflicts.py example.com.zone
www.example.com.: CNAME conflicts with TXT

The script is deliberately simple. It doesn't expand $ORIGIN or relative names, so use it on a provider export with fully qualified names. It also avoids loading the zone into a strict DNS library, because those libraries often reject or silently drop conflicting data, which hides exactly the thing you're looking for.

Checking Live Records With dig

Without an export, you can check a list of names you care about. This loop asks for the most common record types at each name and shows whether a CNAME appears alongside them:

#!/usr/bin/env bash
# Usage: ./check-names.sh ns1.example.net www.example.com shop.example.com
server="$1"; shift
for name in "$@"; do
  echo "== $name"
  for type in CNAME A AAAA MX TXT; do
    dig @"$server" "$name" "$type" +norecurse +noall +answer
  done
done

Query one of your authoritative nameservers directly with +norecurse. That way you see what's actually stored in the zone rather than what a resolver assembles by following the CNAME.

Fix 1: A CNAME at the Zone Apex

This is the most common conflict of all. You want example.com (with nothing in front) to point at something like myapp.herokudns.com or a load balancer hostname, but the apex always has an SOA record and NS records. A CNAME there would break the zone.

You have three good options.

Use ALIAS, ANAME or CNAME Flattening

Many DNS providers offer a record type that behaves like a CNAME but is legal at the apex. The provider resolves the target itself and returns ordinary A and AAAA records to anyone who asks. Names vary:

  • Cloudflare: CNAME flattening, applied automatically to a CNAME at the apex.
  • Amazon Route 53: Alias records, which can point to AWS resources such as CloudFront, Elastic Load Balancing and S3 website endpoints.
  • DNSimple, NS1 and others: ALIAS or ANAME records.

In a provider dashboard, you simply create the record at @ and choose the provider's apex alias type. With Route 53 and the AWS CLI, an alias for a CloudFront distribution looks like this:

aws route53 change-resource-record-sets \
  --hosted-zone-id Z0123456789EXAMPLE \
  --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "d111111abcdef8.cloudfront.net.",
          "EvaluateTargetHealth": false
        }
      }
    }]
  }'

Z2FDTNDATAQYW2 is the fixed hosted zone ID that AWS documents for all CloudFront alias targets. For other AWS resources, look up the correct value in the AWS documentation. Add a matching AAAA alias if the target supports IPv6.

Use A and AAAA Records

If your platform publishes stable IP addresses for apex domains, just add those as normal A and AAAA records. Many hosting platforms document a fixed apex IP for exactly this reason. The trade-off is that if the provider ever changes those IPs, you have to update your records yourself.

example.com.   3600  IN  A     192.0.2.10
example.com.   3600  IN  AAAA  2001:db8::10

Redirect the Apex to www

The classic approach is to keep the apex on A records that point at a small redirect service and put the real CNAME on www. Visitors who type the bare domain are redirected to www.example.com, which can be a normal CNAME to your platform. Some registrars and DNS providers offer this as a built-in "URL forwarding" feature.

Fix 2: A CNAME and an A or AAAA Record on a Subdomain

This happens when you move a subdomain from your own server to a hosted service. The old A record is still there, so the dashboard won't let you add the CNAME.

The fix is simply to replace one with the other, but do it with care:

  1. Lower the TTL on the existing A record a day ahead if you can, so the change takes effect quickly.
  2. Delete the A and AAAA records for the subdomain.
  3. Add the CNAME immediately afterwards.
  4. Check the result against your authoritative nameserver.
dig @ns1.example.net shop.example.com +norecurse +noall +answer
shop.example.com.       300     IN      CNAME   shops.myshopify.com.

There's a short window between deletion and creation where the name doesn't resolve. If that's not acceptable, use your provider's API to make both changes in a single atomic request. Route 53 change batches, for example, apply all the changes together:

{
  "Changes": [
    {
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "shop.example.com.",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [{ "Value": "198.51.100.20" }]
      }
    },
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "shop.example.com.",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{ "Value": "shops.myshopify.com" }]
      }
    }
  ]
}

A Route 53 DELETE must match the existing record exactly, including the TTL and value, so check those first with aws route53 list-resource-record-sets.

Fix 3: A CNAME and a TXT Record on the Same Name

This one often appears when a service asks you to verify ownership of a subdomain that's already a CNAME, or when you try to add an SPF record to a subdomain that's an alias.

Move the TXT Record If the Service Allows It

Many services don't actually need the TXT record on the exact same name. They often accept it on an underscore name, such as _vendor-challenge.www.example.com, which is a separate node in DNS and doesn't conflict. Read the provider's documentation carefully, because some accept either location.

www.example.com.                       300  IN  CNAME  example.vendor.net.
_vendor-challenge.www.example.com.     300  IN  TXT    "verify=7f3c9e1d"

Temporarily Swap the Records

If verification genuinely requires a TXT record on the same name, and the service only checks once, you can:

  1. Remove the CNAME temporarily, or point the name at an A record for a few minutes.
  2. Add the TXT record and complete the verification.
  3. Remove the TXT record and restore the CNAME.

This causes a brief interruption for the subdomain, so do it at a quiet time.

Let the Target Hold the TXT Record

Because resolvers follow the CNAME, a TXT lookup for www.example.com returns the TXT records at the target. If the target belongs to the service that needs verifying, they may already publish the value there. This is exactly how some email services handle DKIM: you add a CNAME, and the TXT key lives on their side.

Fix 4: A CNAME and an MX Record

If a subdomain receives email, it needs MX records, and those can't coexist with a CNAME. For example, support.example.com might have MX records for a helpdesk, and someone later tries to point it at a web host.

You have two clean choices:

  • Split the roles: Use one name for mail and another for the web, such as keeping support.example.com for mail and moving the website to help.example.com.
  • Use A and AAAA records for the web side: Replace the CNAME with the web host's IP addresses, so the MX records can stay.

A related rule is worth knowing here. The target of an MX record must not be a CNAME either (RFC 2181 states this for MX and NS targets). So this is wrong:

example.com.       3600  IN  MX     10 mail.example.com.
mail.example.com.  3600  IN  CNAME  mx.mailprovider.example.

Point the MX record directly at the provider's mail host instead:

example.com.       3600  IN  MX     10 mx.mailprovider.example.

Fix 5: Two Services Want the Same Subdomain

You can only have one CNAME on a name, so two services can't both own app.example.com through DNS alone. The usual answers are:

  • Use separate subdomains: Give each service its own name, such as app.example.com and status.example.com.
  • Put a proxy or CDN in front: Point the name at one CDN or reverse proxy, and route paths to different backends there.
  • Retire the old service first: If you're migrating, delete the old CNAME and then add the new one, ideally after lowering the TTL.

Wildcards and CNAME Conflicts

Wildcard records add a twist. A wildcard such as *.example.com only applies to names that don't otherwise exist in the zone. If you create any record at blog.example.com, the wildcard no longer covers that name for any type.

So if you have a wildcard CNAME and then add a TXT record at blog.example.com, the name now exists and has only the TXT record. Lookups for its A record will no longer match the wildcard and will return no data. This isn't strictly a CNAME conflict, but it produces similar symptoms, and it's worth checking for when a subdomain suddenly stops loading after someone adds a verification record.

Preventing Conflicts in the First Place

A few habits stop most of these problems before they reach production:

  1. Check before you add: Query the name with dig for CNAME, A, AAAA, MX and TXT before creating anything new.
  2. Keep verification records on underscore names where services allow it.
  3. Don't use CNAMEs at the apex of a zone, even if a control panel seems to accept it.
  4. Validate zone files with named-checkzone or your server's equivalent before reloading.
  5. Manage DNS as code if you have many records. Tools such as Terraform or OctoDNS can catch duplicates during review, and providers reject conflicts during plan or apply rather than at 2am.
  6. Document who owns each subdomain, so nobody repoints a name that another team relies on for email or verification.

FAQ: CNAME Conflicts

A CNAME tells resolvers that all data for the name lives at another name. If other records also existed locally, resolvers would have two contradictory sources of truth. The DNS specifications forbid the combination to keep answers consistent.

No. The root of a zone always has SOA and NS records, so a standard CNAME there would conflict with them. Use your provider's ALIAS, ANAME or CNAME flattening feature, or plain A and AAAA records, instead.

Not legally. If a service needs a TXT record on a name that's already a CNAME, check whether it accepts the record on an underscore name such as _service.www.example.com, or temporarily replace the CNAME while you verify.

Yes. RRSIG and NSEC or NSEC3 records can exist alongside a CNAME, because they sign the CNAME and prove what does or doesn't exist at that name. Your DNS provider or signer manages these automatically.

It shouldn't. The DNS specifications say MX and NS targets must be names with address records, not aliases. Some mail servers tolerate it, but others don't, so point MX records directly at the provider's mail host.

Probably not as you expect. Resolvers will usually follow the CNAME and ignore the other record, so lookups for that type return whatever the target has. Query the name with dig to see what the world actually receives, then remove the conflict.

Lower the TTL beforehand, then use your provider's API or a bulk edit to delete the A record and create the CNAME in one change. If you must do it in two steps, add the CNAME immediately after deleting the A record.


Conclusion

CNAME conflicts all come back to one simple rule: a name with a CNAME can't hold anything else, and there can only be one CNAME per name. Once you understand that the CNAME hands the whole name over to its target, the fixes follow naturally. Remove the competing records, move verification records to their own names, or replace the CNAME with address records when the name needs to do more than one job.

At the apex, where SOA and NS records must exist, use your provider's ALIAS or flattening feature or plain A and AAAA records. Check names with dig before you add anything, validate zone files before reloading them, and keep a record of who owns each subdomain. Those habits will stop almost every CNAME conflict before it causes an outage.

Tags :
Share :

Related Posts

What is the difference between an A record and a CNAME record?

What is the difference between an A record and a CNAME record?

The difference between an A record and a CNAME record is what they point to. An A record points a hostname directly at an IPv4 address, such

Dive Deeper
What are the best DNS providers for websites?

What are the best DNS providers for websites?

The best DNS providers for most websites are Cloudflare for a fast, free, easy starting point, Amazon Route 53 if you already run on AWS, **G

Dive Deeper
What are the best public DNS resolvers?

What are the best public DNS resolvers?

The best public DNS resolvers for most people are Cloudflare (1.1.1.1) for speed and privacy, Google Public DNS (8.8.8.8) for reliability and

Dive Deeper