diff --git a/docs/_newsfragments/1749.bugfix.rst b/docs/_newsfragments/1749.bugfix.rst
new file mode 100644
index 0000000..96777e5
--- /dev/null
+++ b/docs/_newsfragments/1749.bugfix.rst
@@ -0,0 +1,3 @@
+The :attr:`Response.downloadable_as <falcon.Response.downloadable_as>` property
+is now correctly encoding non-ASCII filenames as per
+`RFC 6266 <https://tools.ietf.org/html/rfc6266#appendix-D>`_ recommendations.
diff --git a/falcon/response.py b/falcon/response.py
index dc3850b..f3ec961 100644
--- a/falcon/response.py
+++ b/falcon/response.py
@@ -942,9 +942,14 @@ class Response:
         'Content-Disposition',
         """Set the Content-Disposition header using the given filename.
 
-        The value will be used for the *filename* directive. For example,
+        The value will be used for the ``filename`` directive. For example,
         given ``'report.pdf'``, the Content-Disposition header would be set
         to: ``'attachment; filename="report.pdf"'``.
+
+        As per `RFC 6266 <https://tools.ietf.org/html/rfc6266#appendix-D>`_
+        recommendations, non-ASCII filenames will be encoded using the
+        ``filename*`` directive, whereas ``filename`` will contain the US
+        ASCII fallback.
         """,
         format_content_disposition)
 
diff --git a/falcon/response_helpers.py b/falcon/response_helpers.py
index 1d5fec0..81cecc9 100644
--- a/falcon/response_helpers.py
+++ b/falcon/response_helpers.py
@@ -14,6 +14,9 @@
 
 """Utilities for the Response class."""
 
+from falcon.util import uri
+from falcon.util.misc import isascii, secure_filename
+
 
 def header_property(name, doc, transform=None):
     """Create a header getter/setter.
@@ -81,7 +84,25 @@ def format_range(value):
 def format_content_disposition(value):
     """Formats a Content-Disposition header given a filename."""
 
-    return 'attachment; filename="' + value + '"'
+    # NOTE(vytas): RFC 6266, Appendix D.
+    #   Include a "filename" parameter when US-ASCII ([US-ASCII]) is
+    #   sufficiently expressive.
+    if isascii(value):
+        return 'attachment; filename="' + value + '"'
+
+    # NOTE(vytas): RFC 6266, Appendix D.
+    #   * Include a "filename*" parameter where the desired filename cannot be
+    #     expressed faithfully using the "filename" form.  Note that legacy
+    #     user agents will not process this, and will fall back to using the
+    #     "filename" parameter's content.
+    #   * When a "filename*" parameter is sent, to also generate a "filename"
+    #     parameter as a fallback for user agents that do not support the
+    #     "filename*" form, if possible.
+    #   * When a "filename" parameter is included as a fallback (as per above),
+    #     "filename" should occur first, due to parsing problems in some
+    #     existing implementations.
+    return "attachment; filename=%s; filename*=UTF-8''%s" % (
+        secure_filename(value), uri.encode(value))
 
 
 def format_etag_header(value):

diff --git a/tests/test_headers.py b/tests/test_headers.py
index 41f23f8..ce72a22 100644
--- a/tests/test_headers.py
+++ b/tests/test_headers.py
@@ -207,6 +207,16 @@ class RemoveHeaderResource:
         resp.downloadable_as = None
 
 
+class DownloadableResource:
+    def __init__(self, filename):
+        self.filename = filename
+
+    def on_get(self, req, resp):
+        resp.body = 'Hello, World!\n'
+        resp.content_type = falcon.MEDIA_TEXT
+        resp.downloadable_as = self.filename
+
+
 class ContentLengthHeaderResource:
 
     def __init__(self, content_length, body=None, data=None):
@@ -477,6 +487,28 @@ class TestHeaders:
             hist[name] += 1
             assert 1 == hist[name]
 
+    @pytest.mark.parametrize('filename,expected', [
+        ('report.csv', 'attachment; filename="report.csv"'),
+        ('Hello World.txt', 'attachment; filename="Hello World.txt"'),
+        (
+            'Bold Digit 𝟏.txt',
+            'attachment; filename=Bold_Digit_1.txt; '
+            "filename*=UTF-8''Bold%20Digit%20%F0%9D%9F%8F.txt",
+        ),
+        (
+            'Ångström unit.txt',
+            'attachment; filename=A_ngstro_m_unit.txt; '
+            "filename*=UTF-8''%C3%85ngstr%C3%B6m%20unit.txt",
+        ),
+    ])
+    def test_content_disposition_header(self, client, filename, expected):
+        resource = DownloadableResource(filename)
+        client.app.add_route('/', resource)
+        resp = client.simulate_get()
+
+        assert resp.status_code == 200
+        assert resp.headers['Content-Disposition'] == expected
+
     def test_unicode_location_headers(self, client):
         client.app.add_route('/', LocationHeaderUnicodeResource())
 

Response.downloadable_as does not follow RFC 6266 recommendations for UTF-8
At the time of writing, [Response.downloadable_as](https://falcon.readthedocs.io/en/stable/api/request_and_response.html#falcon.Response.downloadable_as) always uses the `attachment; filename="filename.ext"` form regardless of the provided filename. However, [RFC 6266](https://tools.ietf.org/html/rfc6266) specifies that a quoted `filename` shall be interpreted as ISO-8859-1 (although some agents are able to sniff UTF-8), and recommends using `filename*` whenever `filename` cannot be faithfully represented with US-ASCII.
tests/test_headers.py::TestHeaders::test_content_disposition_header[wsgi-Bold tests/test_headers.py::TestHeaders::test_content_disposition_header[wsgi-\xc5ngstr\xf6m
tests/test_headers.py::TestHeaders::test_content_length[wsgi] tests/test_headers.py::TestHeaders::test_declared_content_length_on_head[wsgi] tests/test_headers.py::TestHeaders::test_declared_content_length_overridden_by_no_body[wsgi] tests/test_headers.py::TestHeaders::test_declared_content_length_overriden_by_body_length[wsgi] tests/test_headers.py::TestHeaders::test_declared_content_length_overriden_by_data_length[wsgi] tests/test_headers.py::TestHeaders::test_expires_header[wsgi] tests/test_headers.py::TestHeaders::test_default_value[wsgi] tests/test_headers.py::TestHeaders::test_unset_header[wsgi-True] tests/test_headers.py::TestHeaders::test_unset_header[wsgi-False] tests/test_headers.py::TestHeaders::test_required_header[wsgi] tests/test_headers.py::TestHeaders::test_no_content_length[wsgi-204 tests/test_headers.py::TestHeaders::test_no_content_length[wsgi-304 tests/test_headers.py::TestHeaders::test_content_header_missing[asgi] tests/test_headers.py::TestHeaders::test_content_header_missing[wsgi] tests/test_headers.py::TestHeaders::test_passthrough_request_headers[wsgi] tests/test_headers.py::TestHeaders::test_headers_as_list[wsgi] tests/test_headers.py::TestHeaders::test_default_media_type[wsgi] tests/test_headers.py::TestHeaders::test_override_default_media_type_missing_encoding[False] tests/test_headers.py::TestHeaders::test_response_header_helpers_on_get[wsgi] tests/test_headers.py::TestHeaders::test_content_disposition_header[wsgi-report.csv-attachment; tests/test_headers.py::TestHeaders::test_content_disposition_header[wsgi-Hello tests/test_headers.py::TestHeaders::test_unicode_location_headers[wsgi] tests/test_headers.py::TestHeaders::test_unicode_headers_convertable[wsgi] tests/test_headers.py::TestHeaders::test_response_set_and_get_header[wsgi] tests/test_headers.py::TestHeaders::test_response_append_header[wsgi] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[asgi-ValueError-Set-Cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[asgi-ValueError-set-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[asgi-ValueError-seT-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[asgi-HeaderNotSupported-Set-Cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[asgi-HeaderNotSupported-set-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[asgi-HeaderNotSupported-seT-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[wsgi-ValueError-Set-Cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[wsgi-ValueError-set-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[wsgi-ValueError-seT-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[wsgi-HeaderNotSupported-Set-Cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[wsgi-HeaderNotSupported-set-cookie] tests/test_headers.py::TestHeaders::test_set_cookie_disallowed[wsgi-HeaderNotSupported-seT-cookie] tests/test_headers.py::TestHeaders::test_vary_star[wsgi] tests/test_headers.py::TestHeaders::test_vary_header[wsgi-vary0-accept-encoding] tests/test_headers.py::TestHeaders::test_vary_header[wsgi-vary1-accept-encoding, tests/test_headers.py::TestHeaders::test_content_type_no_body[wsgi] tests/test_headers.py::TestHeaders::test_no_content_type[wsgi-204 tests/test_headers.py::TestHeaders::test_no_content_type[wsgi-304 tests/test_headers.py::TestHeaders::test_custom_content_type[wsgi] tests/test_headers.py::TestHeaders::test_add_link_single[wsgi] tests/test_headers.py::TestHeaders::test_add_link_multiple[wsgi] tests/test_headers.py::TestHeaders::test_add_link_with_title[wsgi] tests/test_headers.py::TestHeaders::test_add_link_with_title_star[wsgi] tests/test_headers.py::TestHeaders::test_add_link_with_anchor[wsgi] tests/test_headers.py::TestHeaders::test_add_link_with_hreflang[wsgi] tests/test_headers.py::TestHeaders::test_add_link_with_hreflang_multi[wsgi] tests/test_headers.py::TestHeaders::test_add_link_with_type_hint[wsgi] tests/test_headers.py::TestHeaders::test_add_link_complex[wsgi] tests/test_headers.py::TestHeaders::test_add_link_crossorigin[wsgi-None-</related/thing>; tests/test_headers.py::TestHeaders::test_add_link_crossorigin[wsgi-anonymous-</related/thing>; tests/test_headers.py::TestHeaders::test_add_link_crossorigin[wsgi-Anonymous-</related/thing>; tests/test_headers.py::TestHeaders::test_add_link_crossorigin[wsgi-AnOnYmOUs-</related/thing>; tests/test_headers.py::TestHeaders::test_add_link_crossorigin[wsgi-Use-Credentials-</related/thing>; tests/test_headers.py::TestHeaders::test_add_link_crossorigin[wsgi-use-credentials-</related/thing>; tests/test_headers.py::TestHeaders::test_add_link_invalid_crossorigin_value[*] tests/test_headers.py::TestHeaders::test_add_link_invalid_crossorigin_value[Allow-all] tests/test_headers.py::TestHeaders::test_add_link_invalid_crossorigin_value[Lax] tests/test_headers.py::TestHeaders::test_add_link_invalid_crossorigin_value[MUST-REVALIDATE] tests/test_headers.py::TestHeaders::test_add_link_invalid_crossorigin_value[Strict] tests/test_headers.py::TestHeaders::test_add_link_invalid_crossorigin_value[deny] tests/test_headers.py::TestHeaders::test_content_length_options[asgi] tests/test_headers.py::TestHeaders::test_content_length_options[wsgi] tests/test_headers.py::TestHeaders::test_set_headers_with_custom_class[wsgi] tests/test_headers.py::TestHeaders::test_headers_with_custom_class_not_callable[wsgi] tests/test_headers.py::TestHeaders::test_request_multiple_header[wsgi]