diff --git a/docs/install.rst b/docs/install.rst
index 1add0799..0389cb11 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -101,9 +101,7 @@ In all other cases, Rally requires ``git 1.9`` or better. Verify with ``git --ve
 JDK
 ~~~
 
-A JDK is required on all machines where you want to launch Elasticsearch. If you use Rally just as a load generator to :doc:`benchmark remote clusters </recipes>`, no JDK is required.
-
-We recommend to use Oracle JDK but you are free to use OpenJDK as well. For details on how to install a JDK check your operating system's documentation pages.
+A JDK is required on all machines where you want to launch Elasticsearch. If you use Rally just as a load generator to :doc:`benchmark remote clusters </recipes>`, no JDK is required. For details on how to install a JDK check your operating system's documentation pages.
 
 To find the JDK, Rally expects the environment variable ``JAVA_HOME`` to be set on all targeted machines. To have more specific control, for example when you want to benchmark across a wide range of Elasticsearch releases, you can also set ``JAVAx_HOME`` where ``x``  is the major version of a JDK (e.g. ``JAVA8_HOME`` would point to a JDK 8 installation). Rally will then choose the highest supported JDK per version of Elasticsearch that is available.
 
diff --git a/docs/telemetry.rst b/docs/telemetry.rst
index d24f0d22..01a7b220 100644
--- a/docs/telemetry.rst
+++ b/docs/telemetry.rst
@@ -31,7 +31,7 @@ You can attach one or more of these telemetry devices to the benchmarked cluster
 jfr
 ---
 
-The ``jfr`` telemetry device enables the `Java Flight Recorder <http://docs.oracle.com/javacomponents/jmc-5-5/jfr-runtime-guide/index.html>`_ on the benchmark candidate. Java Flight Recorder ships only with Oracle JDK, so Rally assumes that Oracle JDK is used for benchmarking.
+The ``jfr`` telemetry device enables the `Java Flight Recorder <http://docs.oracle.com/javacomponents/jmc-5-5/jfr-runtime-guide/index.html>`_ on the benchmark candidate. Up to JDK 11, Java flight recorder ships only with Oracle JDK, so Rally assumes that Oracle JDK is used for benchmarking. If you run benchmarks on JDK 11 or later, Java flight recorder is also available on OpenJDK.
 
 To enable ``jfr``, invoke Rally with ``esrally --telemetry jfr``. ``jfr`` will then write a flight recording file which can be opened in `Java Mission Control <http://www.oracle.com/technetwork/java/javaseproducts/mission-control/java-mission-control-1998576.html>`_. Rally prints the location of the flight recording file on the command line.
 
@@ -44,7 +44,7 @@ Supported telemetry parameters:
 
 .. note::
 
-   The licensing terms of Java flight recorder do not allow you to run it in production environments without a valid license (for details, refer to the `Oracle Java SE Advanced & Suite Products page <http://www.oracle.com/technetwork/java/javaseproducts/overview/index.html>`_). However, running in a QA environment is fine.
+   Up to JDK 11 Java flight recorder ship only with Oracle JDK and the licensing terms do not allow you to run it in production environments without a valid license (for details, refer to the `Oracle Java SE Advanced & Suite Products page <http://www.oracle.com/technetwork/java/javaseproducts/overview/index.html>`_). However, running in a QA environment is fine.
 
 jit
 ---
diff --git a/esrally/mechanic/telemetry.py b/esrally/mechanic/telemetry.py
index e1d750ec..e5f5316f 100644
--- a/esrally/mechanic/telemetry.py
+++ b/esrally/mechanic/telemetry.py
@@ -143,7 +143,7 @@ class FlightRecorder(TelemetryDevice):
     internal = False
     command = "jfr"
     human_name = "Flight Recorder"
-    help = "Enables Java Flight Recorder (requires an Oracle JDK)"
+    help = "Enables Java Flight Recorder (requires an Oracle JDK or OpenJDK 11+)"
 
     def __init__(self, telemetry_params, log_root, java_major_version):
         super().__init__()
@@ -155,15 +155,17 @@ class FlightRecorder(TelemetryDevice):
         io.ensure_dir(self.log_root)
         log_file = "%s/%s-%s.jfr" % (self.log_root, car.safe_name, candidate_id)
 
-        console.println("\n***************************************************************************\n")
-        console.println("[WARNING] Java flight recorder is a commercial feature of the Oracle JDK.\n")
-        console.println("You are using Java flight recorder which requires that you comply with\nthe licensing terms stated in:\n")
-        console.println(console.format.link("http://www.oracle.com/technetwork/java/javase/terms/license/index.html"))
-        console.println("\nBy using this feature you confirm that you comply with these license terms.\n")
-        console.println("Otherwise, please abort and rerun Rally without the \"jfr\" telemetry device.")
-        console.println("\n***************************************************************************\n")
+        # JFR was integrated into OpenJDK 11 and is not a commercial feature anymore.
+        if self.java_major_version < 11:
+            console.println("\n***************************************************************************\n")
+            console.println("[WARNING] Java flight recorder is a commercial feature of the Oracle JDK.\n")
+            console.println("You are using Java flight recorder which requires that you comply with\nthe licensing terms stated in:\n")
+            console.println(console.format.link("http://www.oracle.com/technetwork/java/javase/terms/license/index.html"))
+            console.println("\nBy using this feature you confirm that you comply with these license terms.\n")
+            console.println("Otherwise, please abort and rerun Rally without the \"jfr\" telemetry device.")
+            console.println("\n***************************************************************************\n")
 
-        time.sleep(3)
+            time.sleep(3)
 
         console.info("%s: Writing flight recording to [%s]" % (self.human_name, log_file), logger=self.logger)
 
@@ -174,7 +176,10 @@ class FlightRecorder(TelemetryDevice):
 
     def java_opts(self, log_file):
         recording_template = self.telemetry_params.get("recording-template")
-        java_opts = "-XX:+UnlockDiagnosticVMOptions -XX:+UnlockCommercialFeatures -XX:+DebugNonSafepoints "
+        java_opts = "-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints "
+
+        if self.java_major_version < 11:
+            java_opts += "-XX:+UnlockCommercialFeatures "
 
         if self.java_major_version < 9:
             java_opts += "-XX:+FlightRecorder "

Adjust flight recorder flags for JDK 11
The [open-source release of Java flight recorder](http://openjdk.java.net/jeps/328) is targeted for JDK 11. As a consequence, the JVM flags to activate Java flight recorder will change (it's not a commercial feature anymore). Also, we can remove the licensing warning that we issue (but only from JDK 11 onwards!) and we should change our documentation accordingly (no need for an Oracle JDK anymore to use Java flight recorder)
diff --git a/tests/mechanic/telemetry_test.py b/tests/mechanic/telemetry_test.py
index 82a30ad4..8cc9344f 100644
--- a/tests/mechanic/telemetry_test.py
+++ b/tests/mechanic/telemetry_test.py
@@ -166,14 +166,21 @@ class JfrTests(TestCase):
     def test_sets_options_for_pre_java_9_default_recording_template(self):
         jfr = telemetry.FlightRecorder(telemetry_params={}, log_root="/var/log", java_major_version=random.randint(0, 8))
         java_opts = jfr.java_opts("/var/log/test-recording.jfr")
-        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+UnlockCommercialFeatures -XX:+DebugNonSafepoints -XX:+FlightRecorder "
+        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+UnlockCommercialFeatures -XX:+FlightRecorder "
                          "-XX:FlightRecorderOptions=disk=true,maxage=0s,maxsize=0,dumponexit=true,"
                          "dumponexitpath=/var/log/test-recording.jfr -XX:StartFlightRecording=defaultrecording=true", java_opts)
 
-    def test_sets_options_for_java_9_or_above_default_recording_template(self):
-        jfr = telemetry.FlightRecorder(telemetry_params={}, log_root="/var/log", java_major_version=random.randint(9, 999))
+    def test_sets_options_for_java_9_or_10_default_recording_template(self):
+        jfr = telemetry.FlightRecorder(telemetry_params={}, log_root="/var/log", java_major_version=random.randint(9, 10))
         java_opts = jfr.java_opts("/var/log/test-recording.jfr")
-        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+UnlockCommercialFeatures -XX:+DebugNonSafepoints "
+        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+UnlockCommercialFeatures "
+                         "-XX:StartFlightRecording=maxsize=0,maxage=0s,disk=true,dumponexit=true,filename=/var/log/test-recording.jfr",
+                         java_opts)
+
+    def test_sets_options_for_java_11_or_above_default_recording_template(self):
+        jfr = telemetry.FlightRecorder(telemetry_params={}, log_root="/var/log", java_major_version=random.randint(11, 999))
+        java_opts = jfr.java_opts("/var/log/test-recording.jfr")
+        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints "
                          "-XX:StartFlightRecording=maxsize=0,maxage=0s,disk=true,dumponexit=true,filename=/var/log/test-recording.jfr",
                          java_opts)
 
@@ -182,17 +189,27 @@ class JfrTests(TestCase):
                                        log_root="/var/log",
                                        java_major_version=random.randint(0, 8))
         java_opts = jfr.java_opts("/var/log/test-recording.jfr")
-        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+UnlockCommercialFeatures -XX:+DebugNonSafepoints -XX:+FlightRecorder "
+        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+UnlockCommercialFeatures -XX:+FlightRecorder "
                          "-XX:FlightRecorderOptions=disk=true,maxage=0s,maxsize=0,dumponexit=true,"
                          "dumponexitpath=/var/log/test-recording.jfr -XX:StartFlightRecording=defaultrecording=true,settings=profile",
                          java_opts)
 
-    def test_sets_options_for_java_9_or_above_custom_recording_template(self):
+    def test_sets_options_for_java_9_or_10_custom_recording_template(self):
+        jfr = telemetry.FlightRecorder(telemetry_params={"recording-template": "profile"},
+                                       log_root="/var/log",
+                                       java_major_version=random.randint(9, 10))
+        java_opts = jfr.java_opts("/var/log/test-recording.jfr")
+        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+UnlockCommercialFeatures "
+                         "-XX:StartFlightRecording=maxsize=0,maxage=0s,disk=true,dumponexit=true,"
+                         "filename=/var/log/test-recording.jfr,settings=profile",
+                         java_opts)
+
+    def test_sets_options_for_java_11_or_above_custom_recording_template(self):
         jfr = telemetry.FlightRecorder(telemetry_params={"recording-template": "profile"},
                                        log_root="/var/log",
-                                       java_major_version=random.randint(9, 999))
+                                       java_major_version=random.randint(11, 999))
         java_opts = jfr.java_opts("/var/log/test-recording.jfr")
-        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+UnlockCommercialFeatures -XX:+DebugNonSafepoints "
+        self.assertEqual("-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints "
                          "-XX:StartFlightRecording=maxsize=0,maxage=0s,disk=true,dumponexit=true,"
                          "filename=/var/log/test-recording.jfr,settings=profile",
                          java_opts)

pip install -e .
parse_log_pytest
pytest
pytest pytest-benchmark
apt-get update apt-get install -y gcc python3-pip python3-dev
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
elasticsearch==6.2.0
-e git+https://github.com/elastic/rally.git@a8f4694a7dd6a7b4098f49d93daf14b4e55a090a#egg=esrally
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Jinja2==2.9.5
jsonschema==2.5.1
MarkupSafe==2.0.1
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
psutil==5.4.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
py-cpuinfo==3.2.0
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
pytest-benchmark==3.4.1
tabulate==0.8.1
thespian==3.9.3
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
urllib3==1.22
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: rally
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - elasticsearch==6.2.0
      - jinja2==2.9.5
      - jsonschema==2.5.1
      - markupsafe==2.0.1
      - psutil==5.4.0
      - py-cpuinfo==3.2.0
      - pytest-benchmark==3.4.1
      - tabulate==0.8.1
      - thespian==3.9.3
      - urllib3==1.22
prefix: /opt/conda/envs/rally

tests/mechanic/telemetry_test.py::JfrTests::test_sets_options_for_java_11_or_above_custom_recording_template tests/mechanic/telemetry_test.py::JfrTests::test_sets_options_for_java_11_or_above_default_recording_template tests/mechanic/telemetry_test.py::JfrTests::test_sets_options_for_java_9_or_10_custom_recording_template tests/mechanic/telemetry_test.py::JfrTests::test_sets_options_for_java_9_or_10_default_recording_template tests/mechanic/telemetry_test.py::JfrTests::test_sets_options_for_pre_java_9_custom_recording_template tests/mechanic/telemetry_test.py::JfrTests::test_sets_options_for_pre_java_9_default_recording_template
tests/mechanic/telemetry_test.py::TelemetryTests::test_merges_options_set_by_different_devices tests/mechanic/telemetry_test.py::StartupTimeTests::test_store_calculated_metrics tests/mechanic/telemetry_test.py::MergePartsDeviceTests::test_store_calculated_metrics tests/mechanic/telemetry_test.py::MergePartsDeviceTests::test_store_nothing_if_no_metrics_present tests/mechanic/telemetry_test.py::GcTests::test_sets_options_for_java_9_or_above tests/mechanic/telemetry_test.py::GcTests::test_sets_options_for_pre_java_9 tests/mechanic/telemetry_test.py::CcrStatsTests::test_negative_sample_interval_forbidden tests/mechanic/telemetry_test.py::CcrStatsTests::test_wrong_cluster_name_in_ccr_stats_indices_forbidden tests/mechanic/telemetry_test.py::CcrStatsRecorderTests::test_raises_exception_on_transport_error tests/mechanic/telemetry_test.py::CcrStatsRecorderTests::test_stores_default_ccr_stats tests/mechanic/telemetry_test.py::CcrStatsRecorderTests::test_stores_default_ccr_stats_many_shards tests/mechanic/telemetry_test.py::CcrStatsRecorderTests::test_stores_filtered_ccr_stats tests/mechanic/telemetry_test.py::NodeStatsRecorderTests::test_flatten_indices_fields tests/mechanic/telemetry_test.py::NodeStatsRecorderTests::test_negative_sample_interval_forbidden tests/mechanic/telemetry_test.py::NodeStatsRecorderTests::test_stores_all_nodes_stats tests/mechanic/telemetry_test.py::NodeStatsRecorderTests::test_stores_default_nodes_stats tests/mechanic/telemetry_test.py::ClusterEnvironmentInfoTests::test_stores_cluster_level_metrics_on_attach tests/mechanic/telemetry_test.py::NodeEnvironmentInfoTests::test_stores_node_level_metrics_on_attach tests/mechanic/telemetry_test.py::ExternalEnvironmentInfoTests::test_fallback_when_host_not_available tests/mechanic/telemetry_test.py::ExternalEnvironmentInfoTests::test_stores_all_node_metrics_on_attach tests/mechanic/telemetry_test.py::ClusterMetaDataInfoTests::test_enriches_cluster_nodes_for_elasticsearch_1_x tests/mechanic/telemetry_test.py::ClusterMetaDataInfoTests::test_enriches_cluster_nodes_for_elasticsearch_after_1_x tests/mechanic/telemetry_test.py::GcTimesSummaryTests::test_stores_only_diff_of_gc_times tests/mechanic/telemetry_test.py::IndexStatsTests::test_index_stats_are_per_lap tests/mechanic/telemetry_test.py::IndexStatsTests::test_stores_available_index_stats tests/mechanic/telemetry_test.py::IndexSizeTests::test_stores_index_size_for_data_paths tests/mechanic/telemetry_test.py::IndexSizeTests::test_stores_nothing_if_no_data_path
docs/install.rst docs/telemetry.rst esrally/mechanic/telemetry.py
docs/install.rst docs/telemetry.rst esrally/mechanic/telemetry.py