diff --git a/CHANGES.rst b/CHANGES.rst
index 5d58bb4dbd2cd50ee3c1226d85c7deff4ccba98e..a5742f8278005514ea2a2d5e492c77cd090cdb4d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,7 +8,14 @@ Major overhaul of the whole project. We introduce more modern approaches in
 project layout (like `pyproject`), use new linters and other tools while we
 still support all Python versions from 2.7 up to current 3.12.
 
+We now follow the XDG base directory specification, that tells where config
+(and other) files for an application can be found. You now can also use
+`${XDG_CONFIG_HOME}/diceware/diceware.ini`, or, if the given var is emtpy or
+unset, `${HOME}/.config/diceware/diceware.ini`. The traditional location
+`${HOME}/.diceware.ini` is still supported.
+
 - Officially support Python 3.10 to 3.12.
+- Fixed #86: Follow `XDG`_ base directory specification.
 - Use `ruff` as linter, drop `flake8`.
 - Renew `tox` configuration.
 - Switch to `pyproject`-based project layout, away from using `setup.py`.
diff --git a/README.rst b/README.rst
index 47168d812394e57f1e8f7b3c5424c1f2e868a7f3..b5621048cecc17173847f2b127a88d9194dbc031 100644
--- a/README.rst
+++ b/README.rst
@@ -212,9 +212,14 @@ In custom wordlists we take each line for a valid word and ignore
 empty lines (i.e. lines containing whitespace characters only). Oh,
 and we handle even PGP-signed wordlists.
 
-You can set customized default values in a configuration file
-``.diceware.ini`` (note the leading dot) placed in your home
-directory. This file could look like this::
+You can set customized default values in a configuration file ``.diceware.ini``
+(note the leading dot) placed in your home directory. Since version 1.0 you can
+also use ``${XDG_CONFIG_HOME}/diceware/diceware.ini`` or
+``${HOME}/.config/diceware/diceware.ini`` (if ``${XDG_CONFIG_HOME}`` is
+undefined, see XDG_ for details).
+
+
+This file could look like this::
 
   [diceware]
   num = 7
@@ -432,6 +437,7 @@ People that helped spotting bugs, providing solutions, etc.:
  - `Simon Fondrie-Teitler <https://github.com/simonft>`_ contributed a
    machine-readable copyright file, with improvements from `@anarcat`_
  - `Doug Muth <https://github.com/dmuth>`_ fixed formatting in docs.
+ - `@kmille`_ suggested support for XDG config file locations.
 
 Many thanks to all of them!
 
@@ -480,6 +486,7 @@ details.
 .. _`fork me on github`: http://github.com/ulif/diceware/
 .. _`@heartsucker`: https://github.com/heartsucker/
 .. _`Joseph Bonneau`: https://www.eff.org/about/staff/joseph-bonneau
+.. _`@kmille`: https://github.com/kmille
 .. _`NaturalLanguagePasswords`: https://github.com/NaturalLanguagePasswords
 .. _`prefix code`: https://en.wikipedia.org/wiki/Prefix_code
 .. _`random.SystemRandom`: https://docs.python.org/3.4/library/random.html#random.SystemRandom
@@ -488,3 +495,4 @@ details.
 .. _py.test: https://pytest.org/
 .. _tox: https://tox.testrun.org/
 .. _Sphinx: https://sphinx-doc.org/
+.. _`XDG`: https://specifications.freedesktop.org/basedir-spec/latest/
diff --git a/diceware/config.py b/diceware/config.py
index fb5dd7977966740ddc95597c7bd36aa6aa2edd60..1d994ed25d9ff74f2bbdcb375f6a82c8a5371342 100644
--- a/diceware/config.py
+++ b/diceware/config.py
@@ -42,11 +42,37 @@ RE_WLIST_NAME = re.compile(r'(?![\w\-]+).')
 
 def valid_locations():
     """The list of valid paths we look up for config files.
+
+    We search for config files in the following locations (in that order):
+        1a) dirs in colon-separated var $XDG_CONFIG_DIRS
+        1b) /etc/xdg/diceware/diceware.ini  # if $XDG_CONFIG_DIRS is undefined
+        2a) $XDG_CONFIG_HOME/diceware/diceware.ini  # if $XDG_CONFIG_HOME
+                                                    # is defined
+        2b) $HOME/.config/diceware/diceware.ini  # if $HOME is defined
+                                                 # but not $XDG_CONFIG_HOME
+    Finally we look also for
+        3) ~/.diceware.ini
+
+    Later read configs override prior ones. Therefore an existing
+    `~/.diceware.ini` contains values that cannot be overridden, except on
+    commandline.
+
     """
-    user_home = os.path.expanduser("~")
     result = []
+    user_home = os.path.expanduser("~")
     if user_home != "~":
-        result = [os.path.join(user_home, ".diceware.ini"), ]
+        result.append(os.path.join(user_home, ".diceware.ini"))
+    xdg_dirs = os.getenv("XDG_CONFIG_DIRS", os.path.normcase("/etc/xdg"))
+    if os.getenv("XDG_CONFIG_HOME") or os.getenv("HOME"):
+        xdg_dirs = (
+            os.getenv("XDG_CONFIG_HOME", os.path.join(os.getenv("HOME", ""), ".config"))
+            + ":"
+            + xdg_dirs
+        )
+    result.extend(
+        [os.path.join(x, "diceware", "diceware.ini") for x in xdg_dirs.split(":")]
+    )
+    result.reverse()
     return result
 
 
diff --git a/tests/conftest.py b/tests/conftest.py
index 06b0bb563d52675b0f15d5172ebc6d3dec3f6065..d9c7fb60608668c8f18b94aca9d1f74d25ccb5d5 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -78,8 +78,13 @@ def change_home(monkeypatch, tmpdir):
     If the user running tests has an own .diceware.ini in his home, then
     this will influence tests. Therefore we set the user home to some
     empty dir while tests are running.
+
+    The same applies for XDG-based config files, that might be set on the host
+    running and point to real config files not related to testing.
     """
     monkeypatch.setenv("HOME", str(tmpdir))
+    monkeypatch.delenv("XDG_CONFIG_DIRS", raising=False)
+    monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
     return tmpdir
 
 
diff --git a/tests/test_config.py b/tests/test_config.py
index 7e301962f14f0222a577c3766af92fb275c67f5e..a62aa791d8667ea7962c8583d92184a92dc80aef 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -13,15 +13,41 @@ class TestConfigModule(object):
         assert OPTIONS_DEFAULTS is not None
 
     def test_valid_locations(self, home_dir):
-        # we look for config files in user home and local dir
-        assert valid_locations() == [
-            str(home_dir / ".diceware.ini")
-            ]
+        # we look for config files in "~/.diceware.ini"
+        locations = valid_locations()
+        assert locations == [
+            "/etc/xdg/diceware/diceware.ini",
+            str(home_dir / ".config" / "diceware" / "diceware.ini"),
+            str(home_dir / ".diceware.ini"),
+        ]
 
     def test_valid_locations_wo_user_home(self, monkeypatch):
-        # w/o a valid home we get an empty list
+        # w/o a valid home we get at least a system-wide default location
         monkeypatch.setattr("os.path.expanduser", lambda x: x)
-        assert valid_locations() == []
+        monkeypatch.delenv("HOME")
+        locations = valid_locations()
+        assert locations == ["/etc/xdg/diceware/diceware.ini"]
+
+    def test_valid_locations_considers_xdg_config_home(self, monkeypatch, home_dir):
+        # we consider the $XDG_CONFIG_HOME env var
+        monkeypatch.setenv("XDG_CONFIG_HOME", "/foo")
+        locations = valid_locations()
+        assert locations == [
+            "/etc/xdg/diceware/diceware.ini",
+            "/foo/diceware/diceware.ini",
+            str(home_dir / ".diceware.ini"),
+        ]
+
+    def test_valid_locations_considers_xdg_config_dirs(self, monkeypatch, home_dir):
+        # we consider the $XDG_CONFIG_DIRS env var
+        monkeypatch.setenv("XDG_CONFIG_DIRS", "/foo:/bar")
+        locations = valid_locations()
+        assert locations == [
+            "/bar/diceware/diceware.ini",
+            "/foo/diceware/diceware.ini",
+            str(home_dir / ".config" / "diceware" / "diceware.ini"),
+            str(home_dir / ".diceware.ini"),
+        ]
 
     def test_get_configparser(self, tmpdir):
         # we can parse simple configs