diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
index 9aaebca4..f2fe2ac0 100644
--- a/.github/ISSUE_TEMPLATE/Bug_report.md
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -15,7 +15,7 @@ Please answer the following questions for yourself before submitting an issue. *
 
 ### Issue Details
 
-<!-- Please include all relevant details about the environment you experienced the bug in. -->
+<!-- Please include all relevant details about the environment you experienced the bug in.  If possible, include the result of running `./AdGuardHome -v --version` from the installation directory. -->
 
 * **Version of AdGuard Home server:**
   * <!-- (e.g. v0.123.4) -->
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a3c1f64..870842c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to
 
 ### Added
 
+- Verbose version output with `-v --version` ([#2416]).
 - The ability to set a custom TLD for known local-network hosts ([#2393]).
 - The ability to serve DNS queries on multiple hosts and interfaces ([#1401]).
 - `ips` and `text` DHCP server options ([#2385]).
@@ -45,6 +46,7 @@ and this project adheres to
 [#2385]: https://github.com/AdguardTeam/AdGuardHome/issues/2385
 [#2393]: https://github.com/AdguardTeam/AdGuardHome/issues/2393
 [#2412]: https://github.com/AdguardTeam/AdGuardHome/issues/2412
+[#2416]: https://github.com/AdguardTeam/AdGuardHome/issues/2416
 [#2498]: https://github.com/AdguardTeam/AdGuardHome/issues/2498
 [#2533]: https://github.com/AdguardTeam/AdGuardHome/issues/2533
 [#2541]: https://github.com/AdguardTeam/AdGuardHome/issues/2541
diff --git a/internal/home/options.go b/internal/home/options.go
index 553ed856..293c50b0 100644
--- a/internal/home/options.go
+++ b/internal/home/options.go
@@ -191,16 +191,28 @@ var glinetArg = arg{
 }
 
 var versionArg = arg{
-	"Show the version and exit",
-	"version", "",
-	nil, nil, func(o options, exec string) (effect, error) {
-		return func() error { fmt.Println(version.Full()); os.Exit(0); return nil }, nil
+	description:     "Show the version and exit",
+	longName:        "version",
+	shortName:       "",
+	updateWithValue: nil,
+	updateNoValue:   nil,
+	effect: func(o options, exec string) (effect, error) {
+		return func() error {
+			if o.verbose {
+				fmt.Println(version.Verbose())
+			} else {
+				fmt.Println(version.Full())
+			}
+			os.Exit(0)
+
+			return nil
+		}, nil
 	},
-	func(o options) []string { return nil },
+	serialize: func(o options) []string { return nil },
 }
 
 var helpArg = arg{
-	"Print this help",
+	"Print this help. Show more detailed version description with -v",
 	"help", "",
 	nil, nil, func(o options, exec string) (effect, error) {
 		return func() error { _ = printHelp(exec); os.Exit(64); return nil }, nil
diff --git a/internal/version/norace.go b/internal/version/norace.go
new file mode 100644
index 00000000..5b1ccacb
--- /dev/null
+++ b/internal/version/norace.go
@@ -0,0 +1,5 @@
+// +build !race
+
+package version
+
+const isRace = false
diff --git a/internal/version/race.go b/internal/version/race.go
new file mode 100644
index 00000000..6db3a347
--- /dev/null
+++ b/internal/version/race.go
@@ -0,0 +1,5 @@
+// +build race
+
+package version
+
+const isRace = true
diff --git a/internal/version/version.go b/internal/version/version.go
index df79a9c0..7d0a28e9 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -4,19 +4,9 @@ package version
 import (
 	"fmt"
 	"runtime"
-)
-
-// These are set by the linker.  Unfortunately we cannot set constants during
-// linking, and Go doesn't have a concept of immutable variables, so to be
-// thorough we have to only export them through getters.
-//
-// TODO(a.garipov): Find out if we can get GOARM and GOMIPS values the same way
-// we can GOARCH and GOOS.
-var (
-	channel string = ChannelDevelopment
-	goarm   string
-	gomips  string
-	version string
+	"runtime/debug"
+	"strconv"
+	"strings"
 )
 
 // Channel constants.
@@ -27,21 +17,31 @@ const (
 	ChannelRelease     = "release"
 )
 
+// These are set by the linker.  Unfortunately we cannot set constants during
+// linking, and Go doesn't have a concept of immutable variables, so to be
+// thorough we have to only export them through getters.
+//
+// TODO(a.garipov): Find out if we can get GOARM and GOMIPS values the same way
+// we can GOARCH and GOOS.
+var (
+	channel   string = ChannelDevelopment
+	goarm     string
+	gomips    string
+	version   string
+	buildtime string
+)
+
 // Channel returns the current AdGuard Home release channel.
 func Channel() (v string) {
 	return channel
 }
 
+// vFmtFull defines the format of full version output.
+const vFmtFull = "AdGuard Home, version %s"
+
 // Full returns the full current version of AdGuard Home.
 func Full() (v string) {
-	msg := "AdGuard Home, version %s, channel %s, arch %s %s"
-	if goarm != "" {
-		msg = msg + " v" + goarm
-	} else if gomips != "" {
-		msg = msg + " " + gomips
-	}
-
-	return fmt.Sprintf(msg, version, channel, runtime.GOOS, runtime.GOARCH)
+	return fmt.Sprintf(vFmtFull, version)
 }
 
 // GOARM returns the GOARM value used to build the current AdGuard Home release.
@@ -59,3 +59,137 @@ func GOMIPS() (v string) {
 func Version() (v string) {
 	return version
 }
+
+// Common formatting constants.
+const (
+	sp   = " "
+	nl   = "\n"
+	tb   = "\t"
+	nltb = nl + tb
+)
+
+// writeStrings is a convenient wrapper for strings.(*Builder).WriteString that
+// deals with multiple strings and ignores errors that are guaranteed to be nil.
+func writeStrings(b *strings.Builder, strs ...string) {
+	for _, s := range strs {
+		_, _ = b.WriteString(s)
+	}
+}
+
+// Constants defining the format of module information string.
+const (
+	modInfoAtSep    = "@"
+	modInfoDevSep   = sp
+	modInfoSumLeft  = " (sum: "
+	modInfoSumRight = ")"
+)
+
+// fmtModule returns formatted information about module.  The result looks like:
+//
+//   github.com/Username/module@v1.2.3 (sum: someHASHSUM=)
+//
+func fmtModule(m *debug.Module) (formatted string) {
+	if m == nil {
+		return ""
+	}
+
+	if repl := m.Replace; repl != nil {
+		return fmtModule(repl)
+	}
+
+	b := &strings.Builder{}
+
+	writeStrings(b, m.Path)
+	if ver := m.Version; ver != "" {
+		sep := modInfoAtSep
+		if ver == "(devel)" {
+			sep = modInfoDevSep
+		}
+		writeStrings(b, sep, ver)
+	}
+	if sum := m.Sum; sum != "" {
+		writeStrings(b, modInfoSumLeft, sum, modInfoSumRight)
+	}
+
+	return b.String()
+}
+
+// Constants defining the headers of build information message.
+const (
+	vFmtAGHHdr    = "AdGuard Home"
+	vFmtVerHdr    = "Version: "
+	vFmtChanHdr   = "Channel: "
+	vFmtGoHdr     = "Go version: "
+	vFmtTimeHdr   = "Build time: "
+	vFmtRaceHdr   = "Race: "
+	vFmtGOOSHdr   = "GOOS: " + runtime.GOOS
+	vFmtGOARCHHdr = "GOARCH: " + runtime.GOARCH
+	vFmtGOARMHdr  = "GOARM: "
+	vFmtGOMIPSHdr = "GOMIPS: "
+	vFmtMainHdr   = "Main module:"
+	vFmtDepsHdr   = "Dependencies:"
+)
+
+// Verbose returns formatted build information.  Output example:
+//
+//   AdGuard Home
+//   Version: v0.105.3
+//   Channel: development
+//   Go version: go1.15.3
+//   Build time: 2021-03-30T16:26:08Z+0300
+//   GOOS: darwin
+//   GOARCH: amd64
+//   Race: false
+//   Main module:
+//           ...
+//   Dependencies:
+//           ...
+//
+// TODO(e.burkov): Make it write into passed io.Writer.
+func Verbose() (v string) {
+	b := &strings.Builder{}
+
+	writeStrings(
+		b,
+		vFmtAGHHdr,
+		nl,
+		vFmtVerHdr,
+		version,
+		nl,
+		vFmtChanHdr,
+		channel,
+		nl,
+		vFmtGoHdr,
+		runtime.Version(),
+	)
+	if buildtime != "" {
+		writeStrings(b, nl, vFmtTimeHdr, buildtime)
+	}
+	writeStrings(b, nl, vFmtGOOSHdr, nl, vFmtGOARCHHdr)
+	if goarm != "" {
+		writeStrings(b, nl, vFmtGOARMHdr, "v", goarm)
+	} else if gomips != "" {
+		writeStrings(b, nl, vFmtGOMIPSHdr, gomips)
+	}
+	writeStrings(b, nl, vFmtRaceHdr, strconv.FormatBool(isRace))
+
+	info, ok := debug.ReadBuildInfo()
+	if !ok {
+		return b.String()
+	}
+
+	writeStrings(b, nl, vFmtMainHdr, nltb, fmtModule(&info.Main))
+
+	if len(info.Deps) == 0 {
+		return b.String()
+	}
+
+	writeStrings(b, nl, vFmtDepsHdr)
+	for _, dep := range info.Deps {
+		if depStr := fmtModule(dep); depStr != "" {
+			writeStrings(b, nltb, depStr)
+		}
+	}
+
+	return b.String()
+}
diff --git a/scripts/make/go-build.sh b/scripts/make/go-build.sh
index dbf6f7ac..353ea7e2 100644
--- a/scripts/make/go-build.sh
+++ b/scripts/make/go-build.sh
@@ -54,12 +54,17 @@ esac
 # TODO(a.garipov): Additional validation?
 version="$VERSION"
 
+# Set date and time of the current build.
+buildtime="$(date -u +%FT%TZ%z)"
+
 # Set the linker flags accordingly: set the release channel and the
 # current version as well as goarm and gomips variable values, if the
 # variables are set and are not empty.
 readonly version_pkg='github.com/AdguardTeam/AdGuardHome/internal/version'
-ldflags="-s -w -X ${version_pkg}.version=${version}"
+ldflags="-s -w"
+ldflags="${ldflags} -X ${version_pkg}.version=${version}"
 ldflags="${ldflags} -X ${version_pkg}.channel=${channel}"
+ldflags="${ldflags} -X ${version_pkg}.buildtime=${buildtime}"
 if [ "${GOARM:-}" != '' ]
 then
 	ldflags="${ldflags} -X ${version_pkg}.goarm=${GOARM}"