diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000000000000000000000000000000000000..62a0bdc3ea94047204fccf83ff4a8fc92680c95b
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,47 @@
+name: Build and publish Python distribution to PyPI and TestPyPI
+
+on: push
+
+jobs:
+  build:
+    name: Build distribution
+    if: startsWith(github.ref, 'refs/tags/v') # only publish to PyPI on version tag pushes
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+    - name: Set up Python
+      uses: actions/setup-python@v5.1.0
+      with:
+        python-version: "3.x"
+
+    - name: Install pypa/build
+      run: python3 -m pip install build --user
+    - name: Build a binary wheel and a source tarball
+      run: python3 -m build
+    - name: Store the distribution packages
+      uses: actions/upload-artifact@v4
+      with:
+        name: python-package-distributions
+        path: dist/
+
+  publish-to-pypi:
+    name: Publish Python distribution to PyPI
+    if: startsWith(github.ref, 'refs/tags/v') # only publish to PyPI on version tag pushes
+    needs:
+    - build
+    runs-on: ubuntu-latest
+    environment:
+      name: pypi
+      url: https://pypi.org/p/mwclient
+    permissions:
+      id-token: write  # IMPORTANT: mandatory for trusted publishing
+
+    steps:
+    - name: Download all the dists
+      uses: actions/download-artifact@v4
+      with:
+        name: python-package-distributions
+        path: dist/
+    - name: Publish distribution to PyPI
+      uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst
index 8490c9ef28af80e700cff21f87608de1fad4ad37..9a9a84c704f7eea5828e5c112a34899eb165ac53 100644
--- a/docs/source/development/index.rst
+++ b/docs/source/development/index.rst
@@ -109,3 +109,18 @@ When it is ready, push your branch to your remote:
 
 Then you can open a pull request on GitHub. You should see a URL to do this
 when you push your branch.
+
+Making a release
+----------------
+
+These instructions are for maintainers of the project.
+To cut a release, ensure ``CHANGELOG.md`` is updated, then use
+`bump-my-version <https://callowayproject.github.io/bump-my-version/>`_:
+
+.. code:: bash
+
+    $ pip install bump-my-version
+    $ bump-my-version bump major|minor|patch
+
+Then check the commit looks correct and is tagged vX.Y.Z, and push. The
+``.github/workflows/release.yml`` action will publish to PyPI.
diff --git a/setup.py b/setup.py
index a87ba1da6539c614e4db4d436e565a905079adbf..72a53be67e5d31834112de54a267ae7001f4c1f2 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,9 @@ needs_pytest = set(['pytest', 'test', 'ptr']).intersection(sys.argv)
 pytest_runner = ['pytest-runner'] if needs_pytest else []
 
 setup(name='mwclient',
-      version='0.10.1',  # Use bumpversion to update
+      # See https://mwclient.readthedocs.io/en/latest/development/#making-a-release
+      # for how to update this field and release a new version.
+      version='0.10.1',
       description='MediaWiki API client',
       long_description=README,
       long_description_content_type='text/markdown',