Skip to content
RU
← All articles

DNS Records: How to Add, Check and Fix Them — Enterno.io

In short. A DNS record is a line in your domain's zone shaped as "name — TTL — class — type — value". To add one, open the zone at whichever provider your registrar's NS records point to, pick the type, fill in the name (@ is the root domain, www is a subdomain) and the value. Verify the result with dig, not with a browser: browsers, operating systems and recursive resolvers all cache answers and show you a stale picture.

This is a working guide to operating DNS records: how a zone is put together, how to add and change a record in any control panel, how to handle TXT records (SPF, DKIM, DMARC, ownership verification, ACME), how to verify the result from the command line, and why a change "doesn't apply". A detailed syntax reference for every record type lives in a separate article — DNS record types: A, AAAA, MX, CNAME, TXT and others.

Name resolution path: browser, OS cache, recursive resolver, root server, TLD server and the authoritative zone server
The path of a DNS query: every hop has its own cache — which is exactly why changes are not visible immediately.

How a DNS zone works and what a resource record is

A DNS zone is the set of records for one domain, served by an authoritative name server. The zone holds the truth about the domain: everything resolvers hand out around the world is a copy of that zone with a limited shelf life.

Which server is authoritative is decided by delegation: the registrar stores NS records for the domain, and those servers are the source of truth. That gives you a rule that saves hours of debugging: edit the zone the domain is actually delegated to. If your registrar points at Cloudflare's name servers and you edit records in an old hosting panel, nothing will change.

The first move in any DNS incident is to find out where the domain is delegated: dig +short NS example.com. The panel you are editing must match what that command returns.

What a resource record is made of

A resource record (RR) is defined in RFC 1035 and has five fields. In a classic zone file they read left to right:

  • Name (owner) — the name the record applies to: example.com., www.example.com., _dmarc.example.com.. In web panels this field is usually relative — you type www and the zone is appended for you.
  • TTL — time to live in seconds: how long a caching resolver may keep the answer before asking the authoritative server again.
  • Class — always IN (Internet) in practice; other classes (CH, HS) never appear on the web, and panels usually hide the field.
  • Type — A, AAAA, CNAME, MX, TXT, NS, SOA, SRV, CAA, PTR and others.
  • RDATA — the value itself, whose format depends on the type: an IP address, a domain name, a text string, or a tuple of priority, weight and port.

Records that share a name and a type form an RRset — the unit a resolver fetches and caches as a whole. That has a practical consequence: two A records on the same name cannot have different TTLs, and you cannot update an RRset "partially" — resolvers see it as one indivisible answer.

; a fragment of the example.com zone in BIND format
; addresses come from the ranges reserved for documentation
; (RFC 5737 for IPv4 and RFC 3849 for IPv6)
$ORIGIN example.com.
$TTL 3600

@         3600  IN  SOA   ns1.example.net. hostmaster.example.com. (
                          2026080601   ; Serial
                          7200         ; Refresh
                          900          ; Retry
                          1209600      ; Expire
                          300 )        ; Negative TTL

@         86400 IN  NS    ns1.example.net.
@         86400 IN  NS    ns2.example.net.

@         3600  IN  A     192.0.2.10
@         3600  IN  AAAA  2001:db8::10
www       3600  IN  CNAME example.com.
api       300   IN  A     192.0.2.11

@         3600  IN  MX    10 mx1.example.net.
@         3600  IN  MX    20 mx2.example.net.

@         3600  IN  TXT   "v=spf1 include:_spf.example.net -all"
_dmarc    3600  IN  TXT   "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"

@         3600  IN  CAA   0 issue "letsencrypt.org"

Note the trailing dot in ns1.example.net. and example.com. — it marks a fully qualified domain name. A name without the dot gets $ORIGIN appended to it. That is the source of one of the most common silent failures, covered below.

DNS record types: summary table

The table below is a working cheat sheet: what each type is for, what goes into the value, and where people trip up. Full syntax, formats and use cases for every type are in the reference article DNS record types.

TypePurposeWhat the value holdsCommon mistake
APoint a hostname at an IPv4 addressIPv4 addressA leftover second A record with the old IP: half the traffic lands on a dead server
AAAAPoint a hostname at an IPv6 addressIPv6 addressAAAA exists but the server does not listen on IPv6 — some clients just time out
CNAMEMake a name an alias of another nameA domain name (the canonical one)CNAME at the apex, or a CNAME sitting next to other records on the same name
ALIAS / ANAMEApex-level alias. Not a standard — a provider featureA domain name the provider expands into A/AAAAMoving the zone to a provider without the feature: the record simply disappears
MXWhere inbound mail for the domain is deliveredPriority + mail host nameMX pointing at an IP or at a CNAME; lower number means higher priority, not the reverse
TXTArbitrary text: SPF, DKIM, DMARC, ownership verification, ACMEOne or more strings of up to 255 charactersTwo SPF records on a domain, a stray space in the value, a truncated DKIM key
NSWho is authoritative for the zoneName server hostnamesNS inside the zone disagree with NS at the registrar — edits go nowhere
SOAZone metadata and replication timersPrimary NS, admin mailbox, serial, timersSerial not incremented — secondaries never pull the update
SRVService discovery: where a service is and on which portPriority, weight, port, target hostMissing underscores in names such as _sip._tcp
CAARestrict which CAs may issue certificates for the domainFlag, tag (issue, issuewild, iodef), valueCAA allows one CA while the certificate is ordered from another — issuance is refused
PTRReverse lookup, IP to hostname (rDNS)A domain namePeople try to set it at the domain registrar; in reality the IP owner controls it

Individual deep dives: CNAME vs A record, MX records and email setup, TXT records, NS records, SOA records, SRV records, CAA records, wildcard records.

How to add a DNS record: a procedure for any control panel

Interfaces differ between providers, but the sequence is always the same. It also covers editing an existing record — with the difference that you should lower the TTL first (see the caching section).

  1. Find out where the zone lives. dig +short NS example.com returns the real authoritative servers. An empty answer means the domain is not delegated or has been suspended; check its state with WHOIS.
  2. Open the DNS management section at the provider whose name servers that command returned. It may be the registrar, the host, a CDN or a standalone DNS service.
  3. Pick the record type. A mistake here is quiet but lasting: an A record instead of a CNAME works, yet it stops following the target service when its IP changes.
  4. Fill in the Name (Host, Subdomain) field. This is the least obvious field — details below.
  5. Enter the value. An IP for A, a domain name for CNAME/MX/NS, and for TXT the full string including prefixes such as v=spf1.
  6. Set the TTL. 300 seconds while you are making changes, 3600 or more in steady state.
  7. Save, then verify against the authoritative server rather than a browser: dig @ns1.example.net example.com A +short. If the record is there, you did it right — the rest is a matter of time and caches.

What goes in the Name field: blank, @, www and *

Nearly every panel appends the zone name automatically, so the Name field is relative. Values read as follows:

  • An empty field or @ — the root domain (apex): example.com. They mean the same thing; panels simply label it differently.
  • www — the subdomain www.example.com.
  • api.staging — the nested subdomain api.staging.example.com. Nesting depth is not limited.
  • * — a wildcard: answers for any name that has no records of its own. Details and pitfalls are in the article on wildcard DNS records.
  • _dmarc, _acme-challenge, _sip._tcp — service names with a leading underscore. The underscore is mandatory; the panel will not add it for you.
Typing www.example.com into a Name field that appends the zone for you produces www.example.com.example.com. The record saves without complaint and silently does nothing. Always verify with dig instead of eyeballing the panel.

Why you cannot put a CNAME on the root domain, and what to use instead

The restriction follows from RFC 1034 (section 3.6.2) and its clarification in RFC 2181 (section 10.1): if a name has a CNAME, it must not carry data of any other type. The only exception is for DNSSEC records — RRSIG, NSEC and NSEC3.

The root of a domain, however, is required to carry other types: SOA and NS always live at the apex, and MX and SPF usually join them. So a CNAME on example.com is either rejected by the panel or accepted and quietly breaks mail and delegation.

What to use instead:

  • A and AAAA with real addresses — when the target service gives you stable IPs.
  • ALIAS / ANAME / CNAME flattening — a provider feature: the DNS server resolves the target name itself and returns an ordinary A/AAAA answer. From the outside it looks like an A record, so nothing in the standard is violated. Each provider names the feature differently, and it does not travel with the zone when you migrate.
  • An HTTP redirect from the apex to www — if the service only supports CNAME. The apex then keeps an A record pointing at whatever issues the 301.

A full comparison and selection criteria are in CNAME vs A record.

The trailing dot and other silent typos

In panels that write a BIND zone file underneath, the value mail.example.com without a trailing dot becomes mail.example.com.example.com. The mistake gives no error on save and surfaces only when mail or a CDN stops working.

The rule is simple: for CNAME, MX, NS and SRV values, enter an FQDN and add the trailing dot if the panel shows one in its other records. If the panel never uses dots, do not add one either. Either way, confirm with dig — it shows the resulting name exactly as the server stores it.

A DNS record form with name, type, TTL and value fields, explaining what the @ symbol and the asterisk mean
The Name field is relative: blank and @ mean the root domain, www is a subdomain, * is a wildcard.

TXT records: SPF, DKIM, DMARC and domain verification

TXT is the type carrying the most meaning. Formally it is just text, yet email authentication, proof of domain ownership and automated certificate issuance all rest on it. It is also where most mistakes happen, because the content is validated not by DNS but by the consumer — a mail server, a certificate authority or a verification service.

A key property: a single name can hold several TXT records, and that is perfectly normal. The "only one record" rule is not a DNS constraint but a protocol requirement: one SPF policy per domain, one DMARC policy on the _dmarc name.

Domain ownership verification

Search consoles, mail services, payment and advertising platforms confirm domain ownership through a TXT record holding a unique token. It usually goes on the root domain (@), occasionally on a service name.

@   3600  IN  TXT  "google-site-verification=aBcD...xyz"
@   3600  IN  TXT  "MS=ms12345678"
@   3600  IN  TXT  "v=spf1 include:_spf.example.net -all"

Three separate records on the same name is a correct configuration. Do not try to merge tokens into one string: each service looks for its own prefix at the start of a string and will not find it buried inside someone else's text.

Do not delete verification TXT records after a successful check. Many services re-verify ownership in the background and silently revoke access when the record is gone — which you usually discover at the worst possible moment.

SPF: who may send mail on behalf of the domain

SPF (RFC 7208) lists the sources allowed to send mail using your domain in the envelope sender. It lives in a TXT record on the name mail is sent from.

@   3600  IN  TXT  "v=spf1 ip4:192.0.2.0/24 include:_spf.example.net mx -all"

The mechanisms:

  • ip4: / ip6: — specific sender addresses and subnets.
  • include: — pull in a third party's policy (mail provider, newsletter platform, CRM).
  • a, mx — authorise the addresses from the domain's A records or from its MX hosts.
  • -all — hard fail for everything else, ~all — soft fail, ?all — neutral. Starting with ~all is safer; move to -all once DMARC reports look clean.

Three limits account for most SPF failures:

  • One SPF record per name. Two TXT records starting with v=spf1 produce a permerror — the same outcome as having no SPF at all. Multiple providers are combined with multiple include: mechanisms inside one string.
  • No more than 10 DNS lookups while evaluating the policy (RFC 7208, section 4.6.4). Every include:, a, mx, ptr, exists and redirect consumes the budget, and nested includes count too. Exceeding it is another permerror.
  • SPF is not inherited by subdomains. A policy on example.com says nothing about mail.example.com. Any subdomain that sends mail needs its own record.

DKIM and the selector

DKIM (RFC 6376) publishes the public key a recipient uses to verify a message signature. The key sits in a TXT record at <selector>._domainkey.example.com. The sending system chooses the selector, which is what lets you hold several keys at once and rotate them without downtime.

mail2026._domainkey   3600  IN  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."

The selector is not decoration: if the mail service signs with selector s1 and the record is published as default._domainkey, verification fails. Take the selector strictly from the sending system's instructions or from the DKIM-Signature header of a message you already sent (the s= tag).

DMARC: what to do with messages that fail

DMARC ties SPF and DKIM to the address in the From header and tells the recipient how to treat messages that fail. The record always lives on the _dmarc name.

_dmarc   3600  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com; pct=100; sp=none; adkim=r; aspf=r"
  • p= — the policy for the domain: none (observe only), quarantine (spam folder), reject (refuse during SMTP).
  • sp= — a separate policy for subdomains. Without it, subdomains inherit p=.
  • rua= — where aggregate reports go. Moving to reject without them is flying blind.
  • pct= — the share of messages the policy applies to; useful for tightening gradually.
  • adkim / aspf — alignment strictness: r (relaxed, allows subdomains) or s (strict).

The working sequence: start at p=none with rua, read reports for a few weeks, move to quarantine, and only then to reject. All three mechanisms are covered in detail in the SPF, DKIM and DMARC guide.

ACME and _acme-challenge: TXT records for certificate issuance

The DNS-01 challenge in the ACME protocol proves control of a domain to a certificate authority through a temporary TXT record:

_acme-challenge          3600  IN  TXT  "1qA...token..."
_acme-challenge.staging  3600  IN  TXT  "9zB...token..."

Three practical points:

  • Wildcard certificates are only issued via DNS-01. An HTTP challenge cannot prove control over *.example.com at all.
  • Parallel issuance needs several TXT records on one name. When a single order covers both example.com and *.example.com, both tokens are published on _acme-challenge.example.com at the same time. A client that overwrites the previous value instead of adding to it breaks the order.
  • Delegation via CNAME. If the main DNS provider has no API, point _acme-challenge once as a CNAME to a separate zone where automation is allowed. This is the standard trick for manually managed domains.

The 255-character limit and stitching long values together

DNS does not store text as one arbitrary string but as a set of character-strings, each no longer than 255 octets (RFC 1035, section 3.3.14). The total size of a TXT record may exceed that, using several strings in a row.

This is exactly where DKIM breaks: a 2048-bit RSA public key in base64 runs to roughly 390 characters and does not fit into one string. The correct fix is to split the value into quoted chunks; the consumer concatenates them with no separator (specified for DKIM in RFC 6376 section 3.6.2.2 and for SPF in RFC 7208 section 3.3).

; WRONG: a single string longer than 255 characters
; an authoritative server refuses to load the zone,
; and a web panel silently truncates the tail of the key

; RIGHT: several strings inside one record
mail2026._domainkey  3600  IN  TXT  ( "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1x"
                                      "7Qz3vK9pR2mN4tY6uI8oP0aS1dF3gH5jK7lZ9xC2vB4nM6qW8eR0tY2uI4oP"
                                      "6aS8dF0gH2jK4lZ6xC8vB0nM2qW4eR6tY8uI0oP2aS4dF6gH8jK0lZ2xC4vB"
                                      "IDAQAB" )

The reverse step is reassembling the value when you check it. dig +short prints the strings quoted and space-separated, so you have to join them yourself:

# see how the record is actually split into strings
dig +short TXT mail2026._domainkey.example.com

# reassemble the value with no spaces or quotes
dig +short TXT mail2026._domainkey.example.com \
  | tr -d '"' | tr -d ' \n' ; echo

# length of the reassembled key — if it is shorter than expected,
# the value was truncated when it was entered in the panel
dig +short TXT mail2026._domainkey.example.com \
  | tr -d '"' | tr -d ' \n' | wc -c
If a DKIM signature fails while the record "looks fine", measure the length of the value first. A key truncated at 255 characters looks entirely plausible in a panel and produces no error anywhere.

Quotes, spaces and escaping

In a zone file a space is a separator. Text inside quotes is one string; text without quotes but with spaces inside falls apart into several strings, and the consumer will join them differently than you expect.

  • Always quote TXT values where the panel accepts quotes.
  • A stray space breaks an SPF mechanism: include: _spf.example.net with a space after the colon is no longer an include mechanism but noise, and the whole policy becomes invalid.
  • A quote inside a value is escaped with a backslash: \". In practice SPF, DKIM and DMARC values need no quotes inside — if they appear, the value was copied together with formatting from documentation.
  • An unquoted semicolon starts a comment in a zone file and swallows the rest of a DMARC record. Web panels usually handle this; raw BIND configs do not.

How to check DNS records: dig, nslookup and the authoritative server

Checking in a browser is useless: it shows you not the state of DNS but the sum of several caches. Only a query to the authoritative server gives a trustworthy answer.

All the main types in one command

# overview of a domain: every type you normally care about
for t in NS SOA A AAAA MX TXT CAA; do
  printf '%-5s ' "$t"
  dig +short "$t" example.com | paste -sd' | ' -
  echo
done

# the same thing on one line, easy to paste
dig +noall +answer example.com NS SOA A AAAA MX TXT CAA

# service names that never show up in a general listing
dig +short TXT _dmarc.example.com
dig +short TXT default._domainkey.example.com
dig +short SRV _sip._tcp.example.com

+short keeps only the values, which is handy in scripts. For troubleshooting, +noall +answer is more useful: it shows the name, TTL, class and type — everything you need to spot an extra record or an unexpected TTL.

Querying the authoritative server directly, bypassing caches

This is the core diagnostic move. A resolver may keep serving the old value for another day, while the authoritative server always answers with the current state of the zone.

# 1. find the authoritative servers for the zone
dig +short NS example.com

# 2. ask one of them directly
dig @ns1.example.net example.com A +noall +answer

# 3. confirm the answer is authoritative:
#    the flags line must contain aa (authoritative answer)
dig @ns1.example.net example.com A | grep -E 'flags|ANSWER SECTION' -A2

# 4. compare all authoritative servers with each other —
#    a mismatch means zone replication has not finished
for ns in $(dig +short NS example.com); do
  printf '%-24s %s\n' "$ns" "$(dig +short @"$ns" example.com A | paste -sd, -)"
done

# 5. compare the authoritative answer with public resolvers
for r in 8.8.8.8 1.1.1.1 9.9.9.9; do
  printf '%-12s %s\n' "$r" "$(dig +short @"$r" example.com A | paste -sd, -)"
done

Read the difference between the two answers like this:

  • Authoritative server returns the new value, resolvers return the old one. The change is correct; you are waiting out the TTL. Do nothing.
  • Authoritative server returns the old value. The edit was not saved, or it was made in the wrong zone. Go back to "where is the domain delegated".
  • Different authoritative servers disagree. The zone is out of sync between primary and secondaries; most often the SOA serial was not incremented.

Tracing delegation with +trace

# walk the chain from the root servers down to the zone
dig +trace example.com

# delegation only, without the data answers
dig +trace +nodnssec example.com NS

# check that delegation in the TLD matches
# the NS records inside the zone itself
dig +short NS example.com                      # what the zone says
dig @a.gtld-servers.net example.com NS +noall +authority   # what the TLD says

+trace answers the question "at which level does it break": if the chain stops at the TLD, delegation at the registrar is wrong; if it reaches the authoritative servers and finds nothing, the problem is inside the zone.

Checking SPF, DKIM and DMARC

# SPF: exactly one string with v=spf1 must be found
dig +short TXT example.com | grep -c 'v=spf1'

# DMARC
dig +short TXT _dmarc.example.com

# DKIM for a specific selector
dig +short TXT selector1._domainkey.example.com

# MX records and the addresses of the mail hosts
dig +short MX example.com
for h in $(dig +short MX example.com | awk '{print $2}'); do
  printf '%-28s %s\n' "$h" "$(dig +short A "$h" | paste -sd, -)"
done

# reverse zone: the PTR record for a mail server IP
dig +short -x 192.0.2.25

A DKIM selector cannot be discovered from DNS and cannot be brute-forced — DNS offers no way to list names. Take it from the mail service documentation or from the DKIM-Signature header of a real message.

nslookup on Windows

Windows has no dig out of the box, but it does ship nslookup. The syntax is poorer, yet it is enough to check a record.

nslookup -type=A example.com
nslookup -type=MX example.com
nslookup -type=TXT _dmarc.example.com

REM query a specific server — it is the last argument
nslookup -type=NS example.com 8.8.8.8
nslookup -type=A example.com ns1.example.net

REM interactive mode
nslookup
> set type=TXT
> example.com
> exit

A fuller alternative in PowerShell is Resolve-DnsName example.com -Type MX -Server 8.8.8.8: the output is structured objects, which are much easier to filter.

Terminal showing two dig answers side by side: the authoritative server returns the new address while a public resolver still returns the old one
The authoritative answer and the resolver answer diverge until the old record's TTL expires.

Why DNS changes are not visible: TTL, caches and negative caching

"I changed the record an hour ago and the site still opens the old one" is the most common DNS complaint. In the overwhelming majority of cases the record is correct and what you are seeing is a cache. Here is where those caches live.

Where the answer is cached

  • The recursive resolver — your ISP's or a public one (8.8.8.8, 1.1.1.1) — keeps the answer for exactly TTL seconds from the moment it received it. This is the main layer.
  • The operating system cache: systemd-resolved on Linux, mDNSResponder on macOS, the DNS Client service on Windows.
  • The browser cache. Chrome and its derivatives keep their own DNS cache that lives its own life and is not cleared by clearing history.
  • The application cache. The JVM caches positive answers aggressively by default, and some HTTP clients and connection pools resolve a hostname once at start-up and never re-check. Hence the classic: a service keeps hitting the old IP after a successful migration until it is restarted.
  • Long-lived connections. An established TCP connection will not move to a new IP just because DNS changed.
# Linux (systemd-resolved)
sudo resolvectl flush-caches
resolvectl statistics

# Linux (dnsmasq / nscd, where used)
sudo systemctl restart dnsmasq
sudo systemctl restart nscd

# macOS
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

# Windows
ipconfig /flushdns
ipconfig /displaydns | findstr example.com

# Chrome: open the internal net-internals page,
# switch to the dns section and press Clear host cache

Negative caching: the record that does not exist yet

The most baffling delay happens when you query a name before creating the record. A negative answer (NXDOMAIN — no such name, or NODATA — the name exists but has no records of that type) is cached too. RFC 2308 defines the mechanism: the lifetime is the smaller of the MINIMUM field in the zone's SOA record and the TTL of that SOA record.

# inspect the zone's negative caching parameters
dig +noall +answer SOA example.com

; output: ns1.example.net. hostmaster.example.com.
;         2026080601 7200 900 1209600 300
;                                     ^^^ negative TTL, seconds

# a negative answer shows up as a status with no ANSWER section
dig new.example.com +noall +comments +authority

The practical takeaway: do not query a name before you create the record. One curious dig against a public resolver, and that resolver will keep answering "no such name" for as many seconds as the negative TTL says. That is why one colleague sees a new subdomain immediately and another has to wait half an hour.

The negative TTL is the only SOA parameter that affects clients directly. The other timers (Refresh, Retry, Expire) only govern synchronisation between primary and secondary servers. If you create subdomains often, keep the negative TTL small — 300 seconds is plenty.

The right sequence for changing a record

  1. Lower the TTL a day or two before the change to 300 seconds. Lowering the TTL itself propagates at the old, larger TTL — so "in advance" is not a formality here.
  2. Wait out the old TTL. If it was 86400, that means up to 24 hours; skipping the wait defeats the purpose of lowering it.
  3. Make the change and immediately verify against the authoritative server: dig @ns1.example.net example.com A.
  4. Confirm propagation across resolvers — manually with dig @8.8.8.8 or through the DNS propagation check.
  5. Keep the old server alive for at least one full old TTL, ideally a day: some clients and applications hold caches longer than they should.
  6. Restore the TTL to its working value (3600 or more) once everything is stable.

More on choosing values in the DNS record TTL guide, and on the mechanics of propagation in DNS propagation. Changing the name servers themselves is a separate scenario, covered in how to change your DNS server.

Common DNS record mistakes

Two A records on one name by accident

A migration classic: the new A record is added, the old one is never removed. DNS honestly returns both, clients split roughly evenly between them, and half your users land on a switched-off server. The symptom is deceptive: "the site works every other time", while from your own machine everything looks fine.

# how many A records the name actually has
dig +short A example.com | wc -l
dig +noall +answer A example.com

Multiple A records are a deliberate technique (round-robin), but only while every address is alive. DNS will not notice one of them failing — there is no health checking here.

A CNAME next to other records on the same name

If shop.example.com has a CNAME, it must have no A, no TXT and no MX. Some DNS servers refuse to load such a zone at all; others load it and answer unpredictably, leaving resolvers with contradictory data. It is especially easy to hit by adding a verification TXT record to a name that already points at a CDN via CNAME.

MX pointing at a CNAME or an IP address

An MX value must be a hostname that has an A or AAAA record. RFC 2181 (section 10.3) explicitly forbids an MX target that is an alias, and RFC 5321 requires the same of mail servers. An IP address in an MX field is worse still: some senders will treat it as a hostname and fail to resolve it.

# an MX target must resolve to an address directly, with no CNAME
for h in $(dig +short MX example.com | awk '{print $2}'); do
  echo "$h -> $(dig +short "$h" | paste -sd, -)"
  dig +short CNAME "$h" | grep . && echo "  WARNING: this MX target is a CNAME"
done

The forgotten trailing dot in an FQDN

In BIND-style panels, mx1.example.net without a dot becomes mx1.example.net.example.com. Mail stops arriving while the interface still looks correct. The check is dig +short MX example.com: it prints the full name, including the erroneous tail.

A space in SPF, and two SPF records

Two independent defects with the same outcome — permerror, meaning SPF is treated as absent:

  • an extra space after include: or ip4: splits the mechanism into two tokens;
  • two TXT records with v=spf1 on the same name — typically an old one from a previous provider plus the new one. Merge them into a single string with several include: mechanisms.

Quick check: dig +short TXT example.com | grep -c 'v=spf1' must return exactly 1.

A wildcard covering something other than you expected

Wildcard rules are counter-intuitive:

  • an explicit record always beats a wildcard — if api.example.com has its own A record, the wildcard never applies to that name;
  • a wildcard does not answer for a name that has any other record, even of a different type. A TXT record on test.example.com switches the wildcard off for A queries to that same name;
  • a wildcard does not cover names below existing nodes: *.example.com answers for a.example.com but not for b.a.example.com once a exists as a node in the zone;
  • a wildcard added "just in case" masks typos: a misspelled subdomain resolves instead of honestly returning NXDOMAIN.

DNSSEC breaking after a provider change

The most damaging mistake on this list. If DNSSEC is enabled, the registrar holds a DS record — a fingerprint of the zone's key. Move the zone to another provider and the keys change while the DS at the registrar stays the same. Validating resolvers (which now means most large ones) start returning SERVFAIL, and the domain disappears entirely: website, mail, API. Selectively, too — only for clients whose resolver validates signatures.

# does the registrar publish a DS record
dig +short DS example.com

# does validation pass: the flags line should contain ad (authenticated data)
dig +dnssec example.com A | grep -E '^;; flags'

# explicit chain-of-trust check
delv example.com A
delv +rtrace example.com A

The correct migration order: remove the DS at the registrar, wait out its TTL, move the zone, enable DNSSEC at the new provider, publish the new DS. The signing mechanics are covered in DNSSEC explained.

Editing the wrong zone

The domain is delegated to a CDN while records are edited in the hosting panel; or the domain has two zones at two providers, left over from an old migration. Externally this looks like "DNS has not updated for a week". One command settles it: dig +short NS example.com — then edit where the zone actually lives.

Diagnose by symptom: which record to look at

SymptomRecord to inspectCommandUsual cause
Inbound mail does not arrive MX and the A records of the hosts it points to dig +short MX example.com MX missing, pointing at a CNAME, or at a name with no A record; a forgotten trailing dot
Outbound mail lands in spam TXT (SPF, DKIM, DMARC) and the PTR of the sending IP dig +short TXT example.com, dig +short -x 192.0.2.25 No SPF or two of them; wrong DKIM selector; PTR not set by the IP owner
The site still serves the old version A, AAAA and their TTLs dig @ns1.example.net example.com A versus dig @8.8.8.8 example.com A TTL has not expired; a stale A record remains; the edit was made in the wrong zone
A certificate will not issue CAA and the TXT at _acme-challenge dig +short CAA example.com, dig +short TXT _acme-challenge.example.com CAA authorises a different CA; the token is missing or was overwritten by a second order; validation ran before propagation
The domain does not resolve at all NS, TLD delegation, DS dig +trace example.com, dig +short DS example.com Domain expired or removed from delegation; DS does not match the zone keys — SERVFAIL
A subdomain fails while the root works The subdomain's A/CNAME and any wildcard dig +noall +answer sub.example.com ANY The name was entered as an FQDN in a relative field; the wildcard is disabled by another record type
The root fails while www works A/AAAA at the apex dig +short A example.com A CNAME was placed at the apex and dropped; an ALIAS record did not survive the zone migration
Service verification keeps failing TXT on the required name dig +short TXT example.com The token was merged with another value; the record was created on www instead of the root; a negative answer was cached before the record existed
Works for some people, not for others Divergence between authoritative servers, DNSSEC compare dig @ns across every NS of the zone Zone out of sync (serial not incremented); validating resolvers discard the answer
Timeline of a safe DNS record change: lower the TTL, wait, edit, verify, restore the TTL
A safe record change is four steps spread over time, not a single action.

Bulk operations: zone export, import and zero-downtime migration

Once a zone has dozens of records, retyping them in a new panel is guaranteed to lose something — usually a verification TXT record or an obscure subdomain nobody remembers.

Exporting and importing a zone

  • BIND-format export — available at most DNS providers. It is a plain zone file, and the same format is accepted by the new provider's import.
  • The provider API — more reliable than manual export when you have many zones: you can dump and load records with a script and keep the zone in version control.
  • AXFR (zone transfer) — technically the most complete method, but public providers almost always disable it. If yours allows AXFR from trusted addresses, the dump is a single command.
# dump the zone over AXFR (only works if it is permitted)
dig @ns1.example.net example.com AXFR > example.com.zone

# if AXFR is closed, build a snapshot from the names you know
for name in @ www api mail staging _dmarc _acme-challenge; do
  n=$( [ "$name" = "@" ] && echo example.com || echo "$name.example.com" )
  dig +noall +answer "$n" A AAAA CNAME MX TXT SRV CAA
done > zone-snapshot.txt

# normalise and compare two snapshots (before and after the move)
sort zone-before.txt > a.txt
sort zone-after.txt  > b.txt
diff -u a.txt b.txt

Migrating a zone without downtime

  1. Export the zone from the current provider and save a dig snapshot of every name you know about — that is your reference for comparison.
  2. Create the zone at the new provider and load the records. Leave the NS records at the registrar alone for now.
  3. Compare the zones directly: query the old and the new authoritative servers with identical requests and diff the output line by line. Find discrepancies before the cutover, not after.
  4. Check DNSSEC. If it is enabled, remove the DS at the registrar first and wait out its TTL. Skipping this step takes the whole domain down.
  5. Switch the NS records at the registrar. The delegation TTL in the TLD zone is usually measured in days, and you cannot lower it — it is not yours.
  6. Keep the old zone alive for at least a week: some resolvers will keep hitting the previous servers until the delegation cache expires.
The migration rule: the old zone is switched off last. While both sets of name servers answer identically, the cutover is invisible to users; the moment they start to disagree, you get intermittent failures that are nearly impossible to reproduce.

Monitoring DNS records and alerting on changes

DNS is the single point whose modification instantly redirects all traffic for a domain. Meanwhile several people usually hold write access, and not every provider keeps an audit log. At a minimum, watch:

  • NS and DS — a change here means a change of control over the domain. An unexpected edit warrants immediate investigation.
  • A and AAAA on primary names — a substituted address redirects traffic and enables someone to obtain a certificate for your domain.
  • MX — a hijacked mail route is the quietest and the most damaging change of all.
  • TXT holding SPF, DKIM and DMARC — removing or weakening them opens the domain to spoofed mail.
  • CAA — removing the CA restriction usually precedes an unauthorised certificate issuance.
  • Domain expiry — an expired domain drops out entirely, no matter how carefully the records were configured.

The simplest approach is to take a reference snapshot regularly and compare it with the current state, notifying on any difference:

#!/bin/sh
# /usr/local/bin/dns-diff.sh — compare a zone snapshot with the reference
DOMAIN="example.com"
BASE="/var/lib/dns-watch/$DOMAIN.base"
NOW="/tmp/$DOMAIN.now"

{
  dig +short NS  "$DOMAIN"  | sort
  dig +short DS  "$DOMAIN"  | sort
  dig +short A   "$DOMAIN"  | sort
  dig +short AAAA "$DOMAIN" | sort
  dig +short MX  "$DOMAIN"  | sort
  dig +short TXT "$DOMAIN"  | sort
  dig +short CAA "$DOMAIN"  | sort
} > "$NOW"

if [ -f "$BASE" ] && ! diff -q "$BASE" "$NOW" >/dev/null; then
  diff -u "$BASE" "$NOW" | mail -s "DNS changed: $DOMAIN" ops@example.com
fi
cp "$NOW" "$BASE"

Running it every 15 minutes is enough — a scheduler line such as */15 * * * * under a user allowed to send notifications. If you would rather not run your own infrastructure, website and domain monitoring checks availability and key domain parameters on a schedule and alerts you when something changes.

How to check your DNS records with Enterno.io

  • DNS Lookup — every record type for a domain in one report, with a choice of resolver and a history of checks.
  • Single DNS record check — a targeted query for one name and one type, when you only need to confirm a TXT or a CNAME.
  • DNS propagation check — how the record looks from resolvers in different regions; the answer to "has it propagated yet".
  • MX Lookup — the domain's mail routes and the addresses of the hosts they point to.
  • Email configuration check — SPF, DKIM and DMARC together, with an explanation of why messages end up in spam.
  • WHOIS — registrar, expiry date and the domain's current name servers.
  • Monitoring — scheduled checks of the domain with alerts when key parameters change.

FAQ

How long should I wait after changing a DNS record?

As long as the record's TTL was before the change — that is the upper bound. If the TTL was 3600, every resolver that queries your zone will see the new value within an hour at most. "48 hours" is a myth inherited from name server changes, where the delegation TTL really is measured in days. Check the actual state with the propagation check.

Why does dig show the record while the browser still opens the old site?

Between dig and the browser sit three more caches: the operating system, the browser itself, and connections that are already open. Flush the OS cache, close the tab, try a private window. If only some users are affected, you probably forgot to delete the old A record.

Can I have two A records with different IPs?

Yes — that is round-robin, and resolvers will hand out the addresses in turn. But DNS performs no health checks: if one address stops responding, a share of requests will keep going to it. Round-robin is fine for spreading load across servers you know are alive; it is not a substitute for a load balancer with health checking.

Why does DKIM fail when the record is clearly there?

Two causes cover almost every case. First, the value was truncated at 255 characters: a long key must be entered as several quoted strings. Second, the selector is wrong — the record name must match exactly what your mail service signs with. Measure the reassembled value with dig +short TXT selector._domainkey.example.com | tr -d '" ' | wc -c.

What is negative caching, and why does a new subdomain "not appear"?

If a resolver has already asked for that name and got "no such name", it remembers the negative answer for the period set in the zone's SOA record (typically 300–3600 seconds). So do not check a subdomain before you create it: your own check is what creates the delay you will then complain about.

Who configures the PTR record?

The owner of the IP address — your hosting or internet provider, not the domain owner. The reverse in-addr.arpa zone is delegated together with the address block. Most providers expose PTR in the server control panel; the rest handle it by support request. For a mail server a PTR record is mandatory: without it, messages are almost guaranteed to be treated as spam.

What should I verify after moving hosting?

In order: the NS at the registrar match the zone you are editing; A and AAAA point to the new server with no leftovers; MX records survived the move; TXT records for SPF, DKIM, DMARC and verification tokens were carried over in full; CAA does not block certificate issuance; the DS at the registrar matches the new zone's keys.

DNS records checklist

  • Confirmed where the domain is delegated with dig +short NS example.com — and I am editing that zone.
  • I know what the Name field means in my panel: blank and @ are the root, www is a subdomain, no FQDN needed.
  • The apex carries A/AAAA or ALIAS, never a CNAME.
  • No name with a CNAME carries any other record.
  • MX records point at hostnames with A records, not at CNAMEs or IPs; no trailing dot is missing from the FQDN.
  • Exactly one TXT record with v=spf1, no stray spaces, within the 10-lookup budget.
  • DKIM is published under the correct selector and is not truncated at 255 characters.
  • DMARC exists on _dmarc, starting at p=none with an rua address for reports.
  • Verification TXT records were not deleted after the check passed.
  • TTL was lowered ahead of the change, not at the moment of it.
  • The result was verified against the authoritative server with dig @ns, not in a browser.
  • Old A records and leftovers from the previous host have been removed.
  • With DNSSEC enabled, the migration order was respected: remove the DS first, then change the zone.
  • A reference zone snapshot exists and is compared regularly with alerting on changes.
  • Domain expiry is monitored — an expired domain overrides every other setting.

Check your website right now

Check your site's DNS →
More articles: DNS
DNS
Best Public DNS Servers 2026: Speed, Privacy and Filtering
21.07.2026 · 1 175 views
DNS
How to Flush DNS Cache: Windows, Mac, Linux, Browsers
15.04.2026 · 1 039 views
DNS
MX Records for Email: Step-by-Step Setup Guide
15.04.2026 · 928 views
DNS
DNS Not Resolving: 8 Causes and How to Fix
15.04.2026 · 851 views