nslookup has been called deprecated for roughly twenty years and it is still on every machine you will ever log into. It ships in the same package as dig on Linux, it is built into Windows, and it is the one DNS client a Windows admin, a Linux admin and a network engineer can all use without looking anything up. That is worth something, and it is why the tool refuses to die.
This guide covers what nslookup does well, where its output will actively mislead you, and the handful of flags that make it genuinely useful. Every capture is real output from a Debian 13 host querying an authoritative server for pinglabz.lab across a Cisco Modeling Labs topology, with live public-resolver queries where they make the point better. It is part of the Linux networking commands cluster.
The shape of the command
The syntax is nslookup [options] name [server]. The server goes last, with no @ and no flag, which is the first thing that catches people coming from dig:
j@llmbits:~$ nslookup www.pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
Name: www.pinglabz.lab
Address: 10.77.2.10
Name: www.pinglabz.lab
Address: 2001:db8:77:2::10Two things are already happening that dig would not do. First, one command produced two queries: A and AAAA. nslookup asks for both by default, so a dual-stack name gives you both families in one shot. Second, the Server: block at the top tells you exactly which resolver answered, which is genuinely useful and is the reason a lot of people keep reaching for it.
Leave the server off and it uses whatever /etc/resolv.conf says. Note the extra line that appears:
j@llmbits:~$ nslookup pinglabz.com
Server: 45.90.28.181
Address: 45.90.28.181#53
Non-authoritative answer:
Name: pinglabz.com
Address: 178.128.137.126"Non-authoritative answer" is nslookup's way of saying the aa flag was not set, so this came from a cache rather than from a server that holds the zone. It is the same information dig puts in the flags line, just spelled out. Against the lab's authoritative server that line is absent, which is how you tell the two situations apart.
Record types with -query= or -type=
Both spellings work and mean the same thing. -query= is the documented one, -type= is what most people type:
j@llmbits:~$ nslookup -query=MX pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
pinglabz.lab mail exchanger = 10 mail.pinglabz.lab.
pinglabz.lab mail exchanger = 20 mail2.pinglabz.lab.
j@llmbits:~$ nslookup -query=NS pinglabz.lab 10.77.3.10
pinglabz.lab nameserver = ns1.pinglabz.lab.
pinglabz.lab nameserver = ns2.pinglabz.lab.
j@llmbits:~$ nslookup -query=TXT pinglabz.lab 10.77.3.10
pinglabz.lab text = "v=spf1 ip4:10.77.3.10 ip4:10.77.2.10 -all"
pinglabz.lab text = "pinglabz-lab-verification=phase3"
j@llmbits:~$ nslookup -query=SRV _sip._udp.pinglabz.lab 10.77.3.10
_sip._udp.pinglabz.lab service = 10 60 5060 srv1.pinglabz.lab.nslookup spells out what dig abbreviates. "mail exchanger", "nameserver", "text", "service" instead of MX, NS, TXT, SRV. That verbosity is why it reads well to someone who does not live in DNS, and why it is annoying to parse in a script.
SOA gets broken out field by field automatically, no +multiline needed:
j@llmbits:~$ nslookup -query=SOA pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
pinglabz.lab
origin = ns1.pinglabz.lab
mail addr = hostmaster.pinglabz.lab
serial = 2026081901
refresh = 7200
retry = 3600
expire = 1209600
minimum = 3600That is arguably nicer than dig +multiline. If you are comparing serials between a primary and a secondary at 2am, this is a perfectly good tool for the job.
Reverse lookups need no flag
Give nslookup an address instead of a name and it works it out. No -x, no -t PTR:
j@llmbits:~$ nslookup 10.77.3.10 10.77.3.10
10.3.77.10.in-addr.arpa name = srv1.pinglabz.lab.
j@llmbits:~$ nslookup 10.77.2.10 10.77.3.10
10.2.77.10.in-addr.arpa name = www.pinglabz.lab.Notice the Server: header is gone on a reverse lookup. That inconsistency is characteristic of the tool: the output format shifts depending on what you asked, which is fine for a human and awful for a parser.
What a CNAME looks like
Aliases are shown with the chain resolved, and again both address families come back:
j@llmbits:~$ nslookup portal.pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
portal.pinglabz.lab canonical name = www.pinglabz.lab.
Name: www.pinglabz.lab
Address: 10.77.2.10
Name: www.pinglabz.lab
Address: 2001:db8:77:2::10"Canonical name" is CNAME spelled out. On a real CDN-fronted domain the chain gets long, and nslookup follows all of it:
j@llmbits:~$ nslookup www.pinglabz.com 9.9.9.9
Server: 9.9.9.9
Address: 9.9.9.9#53
Non-authoritative answer:
www.pinglabz.com canonical name = ping-labz.ghost.io.
ping-labz.ghost.io canonical name = ghost.map.fastly.net.
Name: ghost.map.fastly.net
Address: 151.101.131.7
Name: ghost.map.fastly.net
Address: 151.101.195.7
Name: ghost.map.fastly.net
Address: 2a04:4e42:600::775
Name: ghost.map.fastly.net
Address: 2a04:4e42::775Eight addresses across two CNAMEs, all readable without knowing any DNS notation. This is the case where nslookup is arguably the better tool: hand this output to someone who does not do DNS for a living and they can follow it.
Failures and exit status
NXDOMAIN comes back as a plain English complaint:
j@llmbits:~$ nslookup nothere.pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
** server can't find nothere.pinglabz.lab: NXDOMAINThe RCODE is right there at the end of the line, so you still get the real status word. And unlike dig, the exit status is useful:
j@llmbits:~$ nslookup gw.pinglabz.lab 10.77.3.10; echo "exit status: $?"
Server: 10.77.3.10
Address: 10.77.3.10#53
Name: gw.pinglabz.lab
Address: 10.77.0.1
exit status: 0
j@llmbits:~$ nslookup nothere.pinglabz.lab 10.77.3.10 > /dev/null 2>&1; echo "exit status: $?"
exit status: 1That is a real advantage over dig, which returns 0 on NXDOMAIN because the query itself succeeded. If you want a name lookup that fails a shell test when the name does not exist, nslookup and host both give it to you and dig does not.
An unreachable server produces a different failure, with no RCODE at all because nothing answered:
j@llmbits:~$ nslookup -timeout=2 -retry=1 pinglabz.lab 10.77.9.9
;; communications error to 10.77.9.9#53: host unreachable
;; no servers could be reached"Host unreachable" against "server can't find" is the distinction that matters. The first is a routing or firewall problem, the second is a DNS data problem. Different team, usually.
Debug mode, the part people forget exists
This is the flag that makes nslookup competitive with dig, and almost nobody uses it. -debug prints the actual query and response structure:
j@llmbits:~$ nslookup -debug www.pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
------------
QUESTIONS:
www.pinglabz.lab, type = A, class = IN
ANSWERS:
-> www.pinglabz.lab
internet address = 10.77.2.10
ttl = 3600
AUTHORITY RECORDS:
ADDITIONAL RECORDS:
------------
Name: www.pinglabz.lab
Address: 10.77.2.10
------------
QUESTIONS:
www.pinglabz.lab, type = AAAA, class = IN
ANSWERS:
-> www.pinglabz.lab
has AAAA address 2001:db8:77:2::10
ttl = 3600
AUTHORITY RECORDS:
ADDITIONAL RECORDS:
------------
Name: www.pinglabz.lab
Address: 2001:db8:77:2::10Two separate transactions, each with its own question, answer, authority and additional section, and the TTL exposed. That is most of what you wanted dig for. It also makes the dual-query behavior visible: nslookup really is sending two packets for one command.
The flags worth remembering
-query=TYPERecord type. -type= is a synonym. Without it you get A and AAAA.
-debugFull query and response structure with TTLs. The single most underused flag on this tool.
-timeout=NSeconds to wait. Default is 5, which is far too long when probing a dead server.
-retry=NAttempts before giving up. Pair with -timeout to fail fast.
-vcVirtual circuit, meaning use TCP. The equivalent of dig +tcp, and the way to test whether TCP 53 is permitted.
-port=NQuery a nameserver on a non-standard port. Useful against a stub or a test instance.
-norecurseClear the RD bit. Against a cache this asks "do you already know this?" without triggering a lookup.
All of these combine, and combining -timeout with -retry is how you stop a probe from hanging for fifteen seconds:
j@llmbits:~$ nslookup -port=53 -timeout=2 -retry=1 srv1.pinglabz.lab 10.77.3.10
Server: 10.77.3.10
Address: 10.77.3.10#53
Name: srv1.pinglabz.lab
Address: 10.77.3.10
Name: srv1.pinglabz.lab
Address: 2001:db8:77:3::10Truncation is handled, and announced
When a UDP response does not fit, nslookup retries over TCP and tells you it did. Google's TXT records are a reliable way to trigger it:
j@llmbits:~$ nslookup -query=TXT google.com 1.1.1.1
;; Truncated, retrying in TCP mode.
Server: 1.1.1.1
Address: 1.1.1.1#53
Non-authoritative answer:
google.com text = "cisco-ci-domain-verification=47c38bc8c4b74b7233e9053220c1bbe76bcc1cd33c7acf7acd36cd6a5332004b"
google.com text = "onetrust-domain-verification=6d685f1d41a94696ad7ef771f68993e0"
google.com text = "apple-domain-verification=30afIBcvSuDV2PLX"
google.com text = "v=spf1 include:_spf.google.com ~all"
google.com text = "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
[... ten more ...]That first line is a free diagnostic. If you see "Truncated, retrying in TCP mode" and then nothing, TCP 53 is being blocked somewhere in the path, and you have found your intermittent DNS failure.
Interactive mode
Run nslookup with no arguments and it drops into a prompt where you set state once and then fire off queries. This is where it beats dig for exploratory work, because you are not retyping the server on every line. Driven from a here-doc so the whole session is reproducible:
j@llmbits:~$ nslookup
Default server: 10.77.3.10
Address: 10.77.3.10#53
> server 10.77.3.10
> set type=MX
> pinglabz.lab
Server: 10.77.3.10
Address: 10.77.3.10#53
pinglabz.lab mail exchanger = 10 mail.pinglabz.lab.
pinglabz.lab mail exchanger = 20 mail2.pinglabz.lab.
> set type=A
> www.pinglabz.lab
Server: 10.77.3.10
Address: 10.77.3.10#53
Name: www.pinglabz.lab
Address: 10.77.2.10
> exitThe commands worth knowing inside the prompt: server <addr> to switch resolver, set type=X to change record type, set debug or set d2 for increasing verbosity, set all to print current state, and exit to leave. Everything else is a name to look up.
Where nslookup will mislead you
Three real traps, in order of how often they cost people time:
ad for DNSSEC validation, and you cannot see ra to tell whether the server offers recursion at all.
-debug. Since a counting-down TTL is how you spot a cached answer, this matters more than it sounds.
dig +short instead.
There is also the "deprecated" question, which comes up every time somebody uses it. The short version: ISC did announce deprecation years ago, then kept shipping and maintaining it, and current BIND still builds it. The version on this Debian 13 host is nslookup 9.20.26, from BIND 9.20, released in 2026. It is not going anywhere. Use it when it is the right shape for the job, and use dig when you need to see the protocol.
When to reach for which tool
FAQ
Is nslookup really deprecated?
It was announced as deprecated by ISC a long time ago, but it is still built, shipped and maintained as part of BIND, and it is a first-class citizen on Windows. Treat "deprecated" as "not the tool to reach for when you need protocol detail", not as "about to be removed".
Why does nslookup show a different answer from dig?
Usually because they queried different servers. nslookup with no server argument uses /etc/resolv.conf; dig @something does not. Check the Server: line in the nslookup output against the SERVER: line in dig +stats. If they match and the answers still differ, you are looking at a caching difference, and the TTL from nslookup -debug will tell you.
How do I see the TTL in nslookup?
nslookup -debug. There is no other way. It appears in the answers block as ttl = 3600.
Can nslookup do a zone transfer?
In interactive mode, ls -d domain attempts one. On any correctly configured authoritative server it will be refused, which is the outcome you want. If it succeeds against your own infrastructure from an unauthorized host, fix that today. The offensive use of open transfers is covered in the DNS enumeration cluster.
Does nslookup use /etc/hosts?
No. Like dig, it speaks DNS directly to a nameserver and skips the C library resolver entirely, so /etc/hosts, mDNS and NSS modules are all invisible to it. That is exactly why a name can work in ping and fail in nslookup, or the reverse. How Linux resolves names covers the full path.
What is the difference between set debug and set d2?
set debug shows the parsed question and answer sections, as in the -debug capture above. set d2 adds the raw query packet on top of that. Use d2 when you suspect the query itself is malformed or the name is not what you think it is.
Key takeaways
- The server goes last with no flag:
nslookup name server. That single syntax difference is the most common stumble coming fromdig. - It queries A and AAAA by default, so one command covers dual stack. That is a feature for humans and a nuisance for packet counting.
- "Non-authoritative answer" means the
aaflag was not set. Its absence means you reached an authority. -debuggets you questions, answers, authority sections and TTLs, and closes most of the gap withdig.- Exit status is 0 on success and 1 on NXDOMAIN, which makes it scriptable in a way
digis not. - "Truncated, retrying in TCP mode" is a free diagnostic. If the retry then fails, TCP 53 is blocked.
- Do not parse its output. The format changes with the query type. Use
dig +shortorhostfor machine-readable answers. - Reported deprecated, still shipping in BIND 9.20 in 2026, still the only DNS client every operating system agrees on.
For the protocol-level view of the same queries, read the complete dig guide. For the fastest one-line form, see host. For why a name resolves in one tool and not another, read how Linux resolves names. All of them are indexed on the Linux networking commands pillar.