diff --git a/utils/scripts/zone-serial-number-hook.sh b/utils/scripts/zone-serial-number-hook.sh
new file mode 100644
index 0000000..5ee7cbf
--- /dev/null
+++ b/utils/scripts/zone-serial-number-hook.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+# zone-serial-number-hook - Check for missing serial bumps
+#
+# Written in 2020 by Lucas
+#
+# To the extent possible under law, the author(s) have dedicated all
+# copyright and related and neighboring rights to this software to the
+# public domain worldwide. This software is distributed without any
+# warranty.
+#
+# You should have received a copy of the CC0 Public Domain Dedication
+# along with this software. If not, see
+# .
+
+# Requires:
+# - POSIX sh
+# - bc
+# - git
+# - ldns-utils
+
+# Install instructions:
+#
+# cp zone-serial-number-hook "$myrepo/.git/hooks/pre-commit"
+# chmod +x "$myrepo/.git/hooks/pre-commit"
+
+bc_cmp()
+{
+ _X=$1
+ _OP=$2
+ _Y=$3
+
+ _rc=$(bc </dev/null | ldns-read-zone -E SOA | {
+ read -r _name _ttl _class _rrtype _rname _mname _serial _rest
+ printf "%s\n" "${_serial:-0}"
+ }
+}
+
+if git rev-parse --verify HEAD >/dev/null 2>&1; then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=$(git hash-object -t tree /dev/null)
+fi
+
+# Zonefiles names are matched against hooks.zonefile_regex option.
+# Defaults to `\.zone$`.
+zonefile_regex=$(git config --default '\.zone$' hooks.zonefileregex)
+
+needs_serial_bump=$(git diff-index --name-only --cached "$against" |
+ grep -E -- "$zonefile_regex" | {
+ rc=0
+ while read -r filename; do
+ old=$(get_serial "$against:$filename")
+ new=$(get_serial ":$filename")
+ if bc_cmp "$new" "<=" "$old"; then
+ printf "%s\n" "$filename"
+ rc=1
+ fi
+ done
+ return $rc
+})
+
+rc=$?
+if [ $rc -ne 0 ]; then
+ # send all output to standard error
+ exec >&2
+ printf "The following zonefiles require a serial bump:\n"
+ printf "- %s\n" $needs_serial_bump
+fi
+exit $rc