What's Actually Happening
PowerDNS authoritative server or recursor fails to respond to DNS queries. Clients receive SERVFAIL or timeout errors.
The Error You'll See
```bash $ dig @localhost example.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 12345 ```
Backend error:
Backend error: Unable to connect to databaseRefused query:
status: REFUSEDTimeout:
;; connection timed out; no servers could be reachedWhy This Happens
- 1.Backend failure - Database connection lost
- 2.Zone not configured - Domain not in PowerDNS
- 3.DNSSEC errors - Signature validation failures
- 4.Recursion disabled - Server not configured for recursion
- 5.Firewall blocking - Port 53 not accessible
- 6.ACL restrictions - Query source not allowed
- 7.Resource limits - Memory or file descriptors exhausted
Step 1: Check PowerDNS Status
```bash # Check PowerDNS Authoritative: systemctl status pdns
# Check PowerDNS Recursor: systemctl status pdns-recursor
# Check processes: ps aux | grep pdns
# Check configuration: pdnsutil check-zone example.com
# Check listening ports: netstat -tlnp | grep pdns ss -tlnp | grep pdns
# DNS ports: # 53 - UDP and TCP
# Check logs: journalctl -u pdns -f tail -f /var/log/pdns.log
# Check version: pdns_server --version pdns_recursor --version
# Test config: pdns_server --config 2>&1 | head -20 ```
Step 2: Check Backend Connectivity
```bash # PowerDNS supports multiple backends: # - MySQL/MariaDB # - PostgreSQL # - SQLite # - LDAP # - BIND zone files
# Check configured backend: cat /etc/powerdns/pdns.conf | grep launch launch=gmysql
# MySQL backend: launch=gmysql gmysql-host=127.0.0.1 gmysql-user=pdns gmysql-password=password gmysql-dbname=pdns
# Test MySQL connection: mysql -u pdns -p pdns -h 127.0.0.1
# Check database tables: mysql -u pdns -p pdns -e "SHOW TABLES;"
# Required tables: # domains, records, supermasters, comments, etc.
# PostgreSQL backend: launch=gpgsql gpgsql-host=127.0.0.1 gpgsql-user=pdns gpgsql-password=password gpgsql-dbname=pdns
# Test PostgreSQL: psql -U pdns -h 127.0.0.1 pdns
# SQLite backend: launch=gsqlite3 gsqlite3-database=/var/lib/powerdns/pdns.sqlite3
# Test SQLite: sqlite3 /var/lib/powerdns/pdns.sqlite3 ".tables"
# Check backend logs: journalctl -u pdns | grep -i "backend|database|connection" ```
Step 3: Check Zone Configuration
```bash # List zones: pdnsutil list-all-zones
# Check specific zone: pdnsutil show-zone example.com
# Check zone integrity: pdnsutil check-zone example.com
# Add zone: pdnsutil create-zone example.com
# Add record: pdnsutil add-record example.com www A 192.168.1.10
# List records: pdnsutil list-zone example.com
# Check for zone errors: pdnsutil check-zone example.com 2>&1
# Zone in database: mysql -u pdns -p pdns -e "SELECT * FROM domains WHERE name='example.com';" mysql -u pdns -p pdns -e "SELECT * FROM records WHERE domain_id=1;"
# Native zone: pdnsutil create-zone example.com ns1.example.com
# Master zone: # In pdns.conf: master=yes
# Slave zone: slave=yes
# Check zone transfer: pdnsutil check-zone example.com
# Rectify zone (fixes ordering): pdnsutil rectify-zone example.com ```
Step 4: Check DNSSEC Configuration
```bash # Check DNSSEC status: pdnsutil show-zone example.com | grep DNSSEC
# Secure zone: pdnsutil secure-zone example.com
# Check DNSSEC keys: pdnsutil show-zone example.com
# List keys: pdnsutil list-keys example.com
# Generate new key: pdnsutil generate-zone-key example.com zsk pdnsutil generate-zone-key example.com ksk
# Sign zone: pdnsutil rectify-zone example.com
# Check for DNSSEC errors: pdnsutil check-zone example.com
# Disable DNSSEC for zone: pdnsutil disable-dnssec example.com
# DNSSEC in pdns.conf: dnssec=on
# Check signature validity: dig @localhost example.com DNSKEY +dnssec
# Export DS record: pdnsutil export-zone-dnskey example.com
# Check for expired signatures: pdnsutil check-zone example.com | grep -i expired
# Re-sign zone: pdnsutil rectify-zone example.com ```
Step 5: Check Recursor Configuration
```bash # For PowerDNS Recursor:
# Check recursor config: cat /etc/powerdns/recursor.conf
# Allow recursion: allow-from=0.0.0.0/0 # Or restrict: allow-from=192.168.0.0/16,10.0.0.0/8
# Forward zones: forward-zones=example.com=127.0.0.1:5300
# Forward all: forward-zones-recurse=.=8.8.8.8,8.8.4.4
# Local address: local-address=0.0.0.0 local-port=53
# Check recursion works: dig @localhost google.com
# Test forwarding: dig @localhost example.com
# Check recursor logs: journalctl -u pdns-recursor -f
# Recursor API: # Enable API: webserver=yes webserver-address=127.0.0.1 webserver-port=8081 api-key=secret
# Check API: curl -H "X-API-Key: secret" http://localhost:8081/api/v1/servers/localhost
# DNS64: dns64-prefix=64:ff9b::/96 ```
Step 6: Check ACL and Security
```bash # Check allow-from: grep allow-from /etc/powerdns/pdns.conf
# Allow queries from anywhere: allow-from=0.0.0.0/0,::/0
# Or specific networks: allow-from=192.168.0.0/16,10.0.0.0/8,127.0.0.0/8
# Check allow-axfer-ips: allow-axfer-ips=192.168.1.100,192.168.1.101
# For zone transfers
# Check allow-recursion: allow-recursion=192.168.0.0/16,10.0.0.0/8
# Check trusted-notification-proxy: # For slave zones
# Query local address: local-address=0.0.0.0 local-ipv6=::
# Check query-local-address: query-local-address=0.0.0.0
# Test ACL: dig @server-ip example.com # From allowed and disallowed sources
# Check for ACL rejections: journalctl -u pdns | grep -i "denied|rejected|refused" ```
Step 7: Check Firewall
```bash # Check firewall rules: iptables -L -n | grep 53
# Allow DNS: iptables -I INPUT -p udp --dport 53 -j ACCEPT iptables -I INPUT -p tcp --dport 53 -j ACCEPT
# Using ufw: ufw allow 53/udp ufw allow 53/tcp
# Using firewalld: firewall-cmd --add-service=dns --permanent firewall-cmd --reload
# Test port: nc -zuv localhost 53
# Check if listening: ss -ulnp | grep :53 ss -tlnp | grep :53
# Test from client: dig @server-ip example.com
# Check for packet drops: tcpdump -i any udp port 53
# Allow AXFR (zone transfer): iptables -I INPUT -p tcp --dport 53 -s slave-ip -j ACCEPT ```
Step 8: Check Resource Limits
```bash # Check file descriptors: ulimit -n
# Increase file descriptors: ulimit -n 65535
# In systemd service: [Service] LimitNOFILE=65535
# Check memory: free -m
# Check PowerDNS memory: ps aux | grep pdns | awk '{sum+=$6} END {print sum/1024 " MB"}'
# Check cache size (recursor): # In recursor.conf: max-cache-entries=1000000
# Check distributor-threads: distributor-threads=4 receiver-threads=4
# Check timeout settings: query-local-timeout=20 tcp-timeout=10
# Check for OOM: dmesg | grep -i "out of memory"
# Check CPU usage: top -p $(pgrep pdns)
# Adjust threads for load: threads=4 ```
Step 9: Debug Query Issues
```bash # Enable trace logging: # In pdns.conf: loglevel=6 query-logging=yes
# Check logs: journalctl -u pdns -f
# Query with trace: dig @localhost example.com +trace
# Check specific record type: dig @localhost example.com A dig @localhost example.com MX dig @localhost example.com SOA
# Check authoritative: dig @localhost example.com +nssearch
# Force TCP: dig @localhost example.com +tcp
# Check with DNSSEC: dig @localhost example.com +dnssec
# Test backend query: # Direct database check: mysql -u pdns -p pdns -e "SELECT * FROM records WHERE name='www.example.com';"
# Check query stats: # Using API: curl -H "X-API-Key: secret" http://localhost:8081/api/v1/servers/localhost/statistics
# Check ringbuffer: # In recursor.conf: stats-ringbuffer-entries=10000 ```
Step 10: PowerDNS Verification Script
```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-powerdns.sh #!/bin/bash
echo "=== PowerDNS Authoritative ===" systemctl status pdns 2>/dev/null | head -5 || echo "pdns service not found"
echo "" echo "=== PowerDNS Recursor ===" systemctl status pdns-recursor 2>/dev/null | head -5 || echo "pdns-recursor service not found"
echo "" echo "=== Processes ===" ps aux | grep pdns | grep -v grep || echo "No PowerDNS processes"
echo "" echo "=== Listening Ports ===" ss -ulnp 2>/dev/null | grep :53 || netstat -ulnp | grep :53 || echo "Not listening on UDP 53" ss -tlnp 2>/dev/null | grep :53 || netstat -tlnp | grep :53 || echo "Not listening on TCP 53"
echo "" echo "=== Configuration ===" cat /etc/powerdns/pdns.conf 2>/dev/null | grep -E "^launch|^gmysql|^gpgsql|^master|^slave" | head -10 || echo "No pdns.conf"
echo "" echo "=== Backend Connection ===" backend=$(grep "^launch" /etc/powerdns/pdns.conf 2>/dev/null | cut -d= -f2) case $backend in gmysql) host=$(grep "^gmysql-host" /etc/powerdns/pdns.conf 2>/dev/null | cut -d= -f2) db=$(grep "^gmysql-dbname" /etc/powerdns/pdns.conf 2>/dev/null | cut -d= -f2) echo "MySQL backend: $host/$db" mysql -h $host -u pdns -p -e "SELECT 1" 2>/dev/null && echo "Connection OK" || echo "Connection FAILED" ;; gpgsql) echo "PostgreSQL backend" ;; gsqlite3) db=$(grep "^gsqlite3-database" /etc/powerdns/pdns.conf 2>/dev/null | cut -d= -f2) echo "SQLite backend: $db" [ -f "$db" ] && echo "Database exists" || echo "Database NOT FOUND" ;; esac
echo "" echo "=== Zones ===" pdnsutil list-all-zones 2>/dev/null | head -10 || echo "Cannot list zones"
echo "" echo "=== Zone Check ===" for zone in $(pdnsutil list-all-zones 2>/dev/null | head -5); do echo "Checking $zone:" pdnsutil check-zone $zone 2>&1 | tail -2 done
echo "" echo "=== DNSSEC Status ===" pdnsutil list-keys 2>/dev/null | head -5 || echo "No DNSSEC keys"
echo "" echo "=== Recursor Test ===" dig @localhost google.com +short 2>/dev/null | head -3 || echo "Recursion test failed"
echo "" echo "=== Authoritative Test ===" dig @localhost localhost +short 2>/dev/null || echo "Local zone test failed"
echo "" echo "=== Firewall ===" iptables -L -n 2>/dev/null | grep 53 || ufw status 2>/dev/null | grep 53 || echo "Check firewall manually"
echo "" echo "=== Recent Logs ===" journalctl -u pdns --no-pager -n 10 2>/dev/null || echo "No systemd logs"
echo "" echo "=== Recommendations ===" echo "1. Verify backend database is running and accessible" echo "2. Check zone integrity with pdnsutil check-zone" echo "3. Ensure DNSSEC keys are valid if enabled" echo "4. Configure allow-from ACL properly" echo "5. Allow port 53 UDP/TCP in firewall" echo "6. Check recursion settings for recursor" echo "7. Review logs for specific errors" EOF
chmod +x /usr/local/bin/check-powerdns.sh
# Usage: /usr/local/bin/check-powerdns.sh ```
PowerDNS Query Checklist
| Check | Expected |
|---|---|
| Service running | pdns process active |
| Backend connected | Database accessible |
| Zones configured | Domains in PowerDNS |
| DNSSEC valid | Keys not expired |
| ACL configured | allow-from set correctly |
| Firewall open | Port 53 UDP/TCP allowed |
| Recursion | Enabled for recursor |
Verify the Fix
```bash # After fixing PowerDNS query
# 1. Check service systemctl status pdns // Active running
# 2. Check zones pdnsutil list-all-zones // Zones listed
# 3. Test zone dig @localhost example.com // Returns A record
# 4. Check recursion dig @localhost google.com // Returns answer
# 5. Check DNSSEC dig @localhost example.com DNSKEY // Returns DNSKEY
# 6. Monitor logs journalctl -u pdns -f // No errors ```
Related Issues
- [Fix BIND DNS Resolution Failed](/articles/fix-bind-dns-resolution-failed)
- [Fix DNS Server Not Responding](/articles/fix-dns-server-not-responding)
- [Fix DNS Propagation Issues](/articles/fix-dns-propagation-issues)