diff --git a/docs/manpage.rst b/docs/manpage.rst
index 531b7399..4c6356bf 100644
--- a/docs/manpage.rst
+++ b/docs/manpage.rst
@@ -484,6 +484,10 @@ Options controlling ReFrame execution
 
    Set variable ``VAR`` in all tests or optionally only in test ``TEST`` to ``VAL``.
 
+   ``TEST`` can have the form ``[TEST.][FIXT.]*``, in which case ``VAR`` will be set in fixture ``FIXT`` of ``TEST``.
+   Note that this syntax is recursive on fixtures, so that a variable can be set in a fixture arbitrarily deep.
+   ``TEST`` prefix refers to the test class name, *not* the test name, but ``FIXT`` refers to the fixture name *inside* the referenced test.
+
    Multiple variables can be set at the same time by passing this option multiple times.
    This option *cannot* change arbitrary test attributes, but only test variables declared with the :attr:`~reframe.core.pipeline.RegressionMixin.variable` built-in.
    If an attempt is made to change an inexistent variable or a test parameter, a warning will be issued.
@@ -511,8 +515,6 @@ Options controlling ReFrame execution
    Conversions to arbitrary objects are also supported.
    See :class:`~reframe.utility.typecheck.ConvertibleType` for more details.
 
-   The optional ``TEST.`` prefix refers to the test class name, *not* the test name.
-
    Variable assignments passed from the command line happen *before* the test is instantiated and is the exact equivalent of assigning a new value to the variable *at the end* of the test class body.
    This has a number of implications that users of this feature should be aware of:
 
@@ -561,6 +563,10 @@ Options controlling ReFrame execution
 
       Proper handling of boolean variables.
 
+   .. versionchanged:: 3.11.1
+
+      Allow setting variables in fixtures.
+
 
 .. option:: --skip-performance-check
 
diff --git a/reframe/core/meta.py b/reframe/core/meta.py
index a28162a0..5e5b227f 100644
--- a/reframe/core/meta.py
+++ b/reframe/core/meta.py
@@ -535,6 +535,17 @@ class RegressionTestMeta(type):
 
         '''
 
+        if '.' in name:
+            # `name` refers to a fixture variable
+            fixtname, varname = name.split('.', maxsplit=1)
+            try:
+                fixt_space = super().__getattribute__('_rfm_fixture_space')
+            except AttributeError:
+                '''Catch early access attempt to the variable space.'''
+
+            if fixtname in fixt_space:
+                return fixt_space[fixtname].cls.setvar(varname, value)
+
         try:
             var_space = super().__getattribute__('_rfm_var_space')
             if name in var_space:
diff --git a/reframe/core/variables.py b/reframe/core/variables.py
index 48da55e3..b90bf97e 100644
--- a/reframe/core/variables.py
+++ b/reframe/core/variables.py
@@ -281,7 +281,7 @@ class TestVar:
     def _check_is_defined(self):
         if not self.is_defined():
             raise ReframeSyntaxError(
-                f'variable {self._name} is not assigned a value'
+                f'variable {self._name!r} is not assigned a value'
             )
 
     def __repr__(self):

diff --git a/unittests/resources/checks_unlisted/externalvars.py b/unittests/resources/checks_unlisted/externalvars.py
index eaafa529..113061fe 100644
--- a/unittests/resources/checks_unlisted/externalvars.py
+++ b/unittests/resources/checks_unlisted/externalvars.py
@@ -3,19 +3,33 @@ import reframe.utility.sanity as sn
 import reframe.utility.typecheck as typ
 
 
+class Bacon(rfm.RunOnlyRegressionTest):
+    bacon = variable(int, value=-1)
+    executable = 'echo'
+    sanity_patterns = sn.assert_true(1)
+
+
+class Eggs(rfm.RunOnlyRegressionTest):
+    eggs = fixture(Bacon)
+    executable = 'echo'
+    sanity_patterns = sn.assert_true(1)
+
+
 @rfm.simple_test
 class external_x(rfm.RunOnlyRegressionTest):
     valid_systems = ['*']
     valid_prog_environs = ['*']
     foo = variable(int, value=1)
     ham = variable(typ.Bool, value=False)
+    spam = fixture(Eggs)
     executable = 'echo'
 
     @sanity_function
     def assert_foo(self):
         return sn.all([
             sn.assert_eq(self.foo, 3),
-            sn.assert_true(self.ham)
+            sn.assert_true(self.ham),
+            sn.assert_eq(self.spam.eggs.bacon, 10)
         ])
 
 
diff --git a/unittests/test_cli.py b/unittests/test_cli.py
index ce762d2a..4bb5f52e 100644
--- a/unittests/test_cli.py
+++ b/unittests/test_cli.py
@@ -837,13 +837,17 @@ def test_detect_host_topology_file(run_reframe, tmp_path):
 def test_external_vars(run_reframe):
     returncode, stdout, stderr = run_reframe(
         checkpath=['unittests/resources/checks_unlisted/externalvars.py'],
-        more_options=['-S', 'external_x.foo=3', '-S', 'external_y.foo=2',
-                      '-S', 'foolist=3,4', '-S', 'bar=@none',
+        more_options=['-S', 'external_x.foo=3',
                       '-S', 'external_x.ham=true',
-                      '-S', 'external_y.baz=false']
+                      '-S', 'external_x.spam.eggs.bacon=10',
+                      '-S', 'external_y.foo=2',
+                      '-S', 'external_y.baz=false',
+                      '-S', 'foolist=3,4',
+                      '-S', 'bar=@none']
     )
+    assert 'PASSED' in stdout
+    assert 'Ran 6/6 test case(s)' in stdout
     assert 'Traceback' not in stdout
-    assert 'Ran 2/2 test case(s)' in stdout
     assert 'Traceback' not in stderr
     assert returncode == 0
 

Fixture variables cannot be set from the command line
This is very easy to reproduce by simply trying doing `-S fixture_class.var=val`. You will notice that the variable is not set. This is due to the following:

https://github.com/eth-cscs/reframe/blob/f44e37c781da8d4bbc20daf52597458ffb5da377/reframe/frontend/loader.py#L173-L205

Although we set the variables in all the tests in the test registry, this does not include the fixtures, which are actually instantiated just after.
unittests/test_cli.py::test_external_vars
unittests/test_cli.py::test_check_success unittests/test_cli.py::test_check_restore_session_failed unittests/test_cli.py::test_check_restore_session_succeeded_test unittests/test_cli.py::test_check_restore_session_check_search_path unittests/test_cli.py::test_check_success_force_local unittests/test_cli.py::test_report_file_with_sessionid unittests/test_cli.py::test_report_ends_with_newline unittests/test_cli.py::test_check_failure unittests/test_cli.py::test_check_setup_failure unittests/test_cli.py::test_check_kbd_interrupt unittests/test_cli.py::test_check_sanity_failure unittests/test_cli.py::test_dont_restage unittests/test_cli.py::test_checkpath_symlink unittests/test_cli.py::test_performance_check_failure unittests/test_cli.py::test_perflogdir_from_env unittests/test_cli.py::test_performance_report unittests/test_cli.py::test_skip_system_check_option unittests/test_cli.py::test_skip_prgenv_check_option unittests/test_cli.py::test_sanity_of_checks unittests/test_cli.py::test_unknown_system unittests/test_cli.py::test_sanity_of_optconfig unittests/test_cli.py::test_checkpath_recursion unittests/test_cli.py::test_same_output_stage_dir unittests/test_cli.py::test_execution_modes unittests/test_cli.py::test_timestamp_option unittests/test_cli.py::test_timestamp_option_default unittests/test_cli.py::test_list_empty_prgenvs_check_and_options unittests/test_cli.py::test_list_check_with_empty_prgenvs unittests/test_cli.py::test_list_empty_prgenvs_in_check_and_options unittests/test_cli.py::test_list_with_details unittests/test_cli.py::test_list_concretized unittests/test_cli.py::test_list_tags unittests/test_cli.py::test_filtering_multiple_criteria unittests/test_cli.py::test_show_config_all unittests/test_cli.py::test_show_config_param unittests/test_cli.py::test_show_config_unknown_param unittests/test_cli.py::test_show_config_null_param unittests/test_cli.py::test_verbosity unittests/test_cli.py::test_verbosity_with_check unittests/test_cli.py::test_quiesce_with_check unittests/test_cli.py::test_failure_stats unittests/test_cli.py::test_maxfail_option unittests/test_cli.py::test_maxfail_invalid_option unittests/test_cli.py::test_maxfail_negative unittests/test_cli.py::test_detect_host_topology unittests/test_cli.py::test_detect_host_topology_file unittests/test_cli.py::test_external_vars_invalid_expr unittests/test_cli.py::test_fixture_registry_env_sys unittests/test_cli.py::test_fixture_resolution unittests/test_cli.py::test_dynamic_tests unittests/test_cli.py::test_dynamic_tests_filtering