diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/MonitorResourcesTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/MonitorResourcesTest.java
new file mode 100644
index 00000000000..4481ec62643
--- /dev/null
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/MonitorResourcesTest.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.waitAtMost;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
+import org.apache.logging.log4j.core.config.properties.PropertiesConfiguration;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.core.util.Source;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.CleanupMode;
+import org.junit.jupiter.api.io.TempDir;
+
+public class MonitorResourcesTest {
+
+    @Test
+    void test_reconfiguration(@TempDir(cleanup = CleanupMode.ON_SUCCESS) final Path tempDir) throws IOException {
+        final ConfigurationBuilder<PropertiesConfiguration> configBuilder =
+                ConfigurationBuilderFactory.newConfigurationBuilder(PropertiesConfiguration.class);
+        final Path configFile = tempDir.resolve("log4j.xml");
+        final Path externalResourceFile1 = tempDir.resolve("external-resource-1.txt");
+        final Path externalResourceFile2 = tempDir.resolve("external-resource-2.txt");
+        final ConfigurationSource configSource = new ConfigurationSource(new Source(configFile), new byte[] {}, 0);
+        final int monitorInterval = 3;
+
+        final ComponentBuilder<?> monitorResourcesComponent = configBuilder.newComponent("MonitorResources");
+        monitorResourcesComponent.addComponent(configBuilder
+                .newComponent("MonitorResource")
+                .addAttribute("uri", externalResourceFile1.toUri().toString()));
+        monitorResourcesComponent.addComponent(configBuilder
+                .newComponent("MonitorResource")
+                .addAttribute("uri", externalResourceFile2.toUri().toString()));
+
+        final Configuration config = configBuilder
+                .setConfigurationSource(configSource)
+                .setMonitorInterval(String.valueOf(monitorInterval))
+                .addComponent(monitorResourcesComponent)
+                .build();
+
+        try (final LoggerContext loggerContext = Configurator.initialize(config)) {
+            assertMonitorResourceFileNames(
+                    loggerContext,
+                    configFile.getFileName().toString(),
+                    externalResourceFile1.getFileName().toString(),
+                    externalResourceFile2.getFileName().toString());
+            Files.write(externalResourceFile2, Collections.singletonList("a change"));
+            waitAtMost(2 * monitorInterval, TimeUnit.SECONDS).until(() -> loggerContext.getConfiguration() != config);
+        }
+    }
+
+    @Test
+    @LoggerContextSource("config/MonitorResource/log4j.xml")
+    void test_config_of_type_XML(final LoggerContext loggerContext) {
+        assertMonitorResourceFileNames(loggerContext, "log4j.xml");
+    }
+
+    @Test
+    @LoggerContextSource("config/MonitorResource/log4j.json")
+    void test_config_of_type_JSON(final LoggerContext loggerContext) {
+        assertMonitorResourceFileNames(loggerContext, "log4j.json");
+    }
+
+    @Test
+    @LoggerContextSource("config/MonitorResource/log4j.yaml")
+    void test_config_of_type_YAML(final LoggerContext loggerContext) {
+        assertMonitorResourceFileNames(loggerContext, "log4j.yaml");
+    }
+
+    @Test
+    @LoggerContextSource("config/MonitorResource/log4j.properties")
+    void test_config_of_type_properties(final LoggerContext loggerContext) {
+        assertMonitorResourceFileNames(loggerContext, "log4j.properties");
+    }
+
+    private static void assertMonitorResourceFileNames(final LoggerContext loggerContext, final String configFileName) {
+        assertMonitorResourceFileNames(loggerContext, configFileName, "external-file-1.txt", "external-file-2.txt");
+    }
+
+    private static void assertMonitorResourceFileNames(
+            final LoggerContext loggerContext, final String configFileName, final String... externalResourceFileNames) {
+        final Set<Source> sources = loggerContext
+                .getConfiguration()
+                .getWatchManager()
+                .getConfigurationWatchers()
+                .keySet();
+        final Set<String> actualFileNames =
+                sources.stream().map(source -> source.getFile().getName()).collect(Collectors.toSet());
+        final Set<String> expectedFileNames = new LinkedHashSet<>();
+        expectedFileNames.add(configFileName);
+        expectedFileNames.addAll(Arrays.asList(externalResourceFileNames));
+        assertThat(actualFileNames).as("watch manager sources: %s", sources).isEqualTo(expectedFileNames);
+    }
+}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfigTest.java
index 42cdcb3071c..c1ede9cb447 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfigTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactoryConfigTest.java
@@ -45,6 +45,17 @@ void testConfigWaitStrategyFactory(final LoggerContext context) {
                 asyncWaitStrategyFactory instanceof YieldingWaitStrategyFactory);
     }
 
+    @Test
+    @LoggerContextSource("AsyncWaitStrategyFactoryConfigTest.properties")
+    void testConfigWaitStrategyFactoryFromProperties(final LoggerContext context) {
+        final AsyncWaitStrategyFactory asyncWaitStrategyFactory =
+                context.getConfiguration().getAsyncWaitStrategyFactory();
+        assertEquals(YieldingWaitStrategyFactory.class, asyncWaitStrategyFactory.getClass());
+        assertThat(
+                "factory is YieldingWaitStrategyFactory",
+                asyncWaitStrategyFactory instanceof YieldingWaitStrategyFactory);
+    }
+
     @Test
     @LoggerContextSource("AsyncWaitStrategyFactoryConfigTest.xml")
     void testWaitStrategy(final LoggerContext context) {
diff --git a/log4j-core-test/src/test/resources/AsyncWaitStrategyFactoryConfigTest.properties b/log4j-core-test/src/test/resources/AsyncWaitStrategyFactoryConfigTest.properties
new file mode 100644
index 00000000000..e8a76f6fda5
--- /dev/null
+++ b/log4j-core-test/src/test/resources/AsyncWaitStrategyFactoryConfigTest.properties
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+strategy.type = AsyncWaitStrategyFactory
+strategy.class = org.apache.logging.log4j.core.async.AsyncWaitStrategyFactoryConfigTest$YieldingWaitStrategyFactory
diff --git a/log4j-core-test/src/test/resources/config/MonitorResource/log4j.json b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.json
new file mode 100644
index 00000000000..26c566af41b
--- /dev/null
+++ b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.json
@@ -0,0 +1,15 @@
+{
+  "Configuration": {
+    "monitorInterval": "30",
+    "MonitorResources": {
+      "MonitorResource": [
+        {
+          "uri": "file://path/to/external-file-1.txt"
+        },
+        {
+          "uri": "file://path/to/external-file-2.txt"
+        }
+      ]
+    }
+  }
+}
diff --git a/log4j-core-test/src/test/resources/config/MonitorResource/log4j.properties b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.properties
new file mode 100644
index 00000000000..dd772d9ff10
--- /dev/null
+++ b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.properties
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+monitorInterval = 30
+monitorResources.type = MonitorResources
+monitorResources.0.type = MonitorResource
+monitorResources.0.uri = file://path/to/external-file-1.txt
+monitorResources.1.type = MonitorResource
+monitorResources.1.uri = file://path/to/external-file-2.txt
diff --git a/log4j-core-test/src/test/resources/config/MonitorResource/log4j.xml b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.xml
new file mode 100644
index 00000000000..1529167d56f
--- /dev/null
+++ b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to you under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd"
+               monitorInterval="30">
+  <MonitorResources>
+    <MonitorResource uri="file://path/to/external-file-1.txt"/>
+    <MonitorResource uri="file://path/to/external-file-2.txt"/>
+  </MonitorResources>
+</Configuration>
diff --git a/log4j-core-test/src/test/resources/config/MonitorResource/log4j.yaml b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.yaml
new file mode 100644
index 00000000000..11f804108b7
--- /dev/null
+++ b/log4j-core-test/src/test/resources/config/MonitorResource/log4j.yaml
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+Configuration:
+  monitorInterval: '30'
+  MonitorResources:
+    MonitorResource:
+      - uri: "file://path/to/external-file-1.txt"
+      - uri: "file://path/to/external-file-2.txt"
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 5b60a7727b3..41fad82cd3f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -132,6 +132,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
     private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<>();
     private ConcurrentMap<String, LoggerConfig> loggerConfigs = new ConcurrentHashMap<>();
     private List<CustomLevelConfig> customLevels = Collections.emptyList();
+    private Set<MonitorResource> monitorResources = Collections.emptySet();
     private final ConcurrentMap<String, String> propertyMap = new ConcurrentHashMap<>();
     private final Interpolator tempLookup = new Interpolator(propertyMap);
     private final StrSubstitutor runtimeStrSubstitutor = new RuntimeStrSubstitutor(tempLookup);
@@ -267,6 +268,7 @@ public void initialize() {
         setup();
         setupAdvertisement();
         doConfigure();
+        watchMonitorResources();
         setState(State.INITIALIZED);
         LOGGER.debug("Configuration {} initialized", this);
     }
@@ -322,10 +324,10 @@ public void start() {
         }
         LOGGER.info("Starting configuration {}...", this);
         this.setStarting();
-        if (watchManager.getIntervalSeconds() >= 0) {
+        if (isConfigurationMonitoringEnabled()) {
             LOGGER.info(
                     "Start watching for changes to {} every {} seconds",
-                    getConfigurationSource(),
+                    watchManager.getConfigurationWatchers().keySet(),
                     watchManager.getIntervalSeconds());
             watchManager.start();
         }
@@ -347,6 +349,21 @@ public void start() {
         LOGGER.info("Configuration {} started.", this);
     }
 
+    private boolean isConfigurationMonitoringEnabled() {
+        return this instanceof Reconfigurable && watchManager.getIntervalSeconds() > 0;
+    }
+
+    private void watchMonitorResources() {
+        if (isConfigurationMonitoringEnabled()) {
+            monitorResources.forEach(monitorResource -> {
+                Source source = new Source(monitorResource.getUri());
+                final ConfigurationFileWatcher watcher = new ConfigurationFileWatcher(
+                        this, (Reconfigurable) this, listeners, source.getFile().lastModified());
+                watchManager.watch(source, watcher);
+            });
+        }
+    }
+
     private boolean hasAsyncLoggers() {
         if (root instanceof AsyncLoggerConfig) {
             return true;
@@ -729,9 +746,16 @@ protected void doConfigure() {
             } else if (child.isInstanceOf(AsyncWaitStrategyFactoryConfig.class)) {
                 final AsyncWaitStrategyFactoryConfig awsfc = child.getObject(AsyncWaitStrategyFactoryConfig.class);
                 asyncWaitStrategyFactory = awsfc.createWaitStrategyFactory();
+            } else if (child.isInstanceOf(MonitorResources.class)) {
+                monitorResources = child.getObject(MonitorResources.class).getResources();
             } else {
                 final List<String> expected = Arrays.asList(
-                        "\"Appenders\"", "\"Loggers\"", "\"Properties\"", "\"Scripts\"", "\"CustomLevels\"");
+                        "\"Appenders\"",
+                        "\"Loggers\"",
+                        "\"Properties\"",
+                        "\"Scripts\"",
+                        "\"CustomLevels\"",
+                        "\"MonitorResources\"");
                 LOGGER.error(
                         "Unknown object \"{}\" of type {} is ignored: try nesting it inside one of: {}.",
                         child.getName(),
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/MonitorResource.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/MonitorResource.java
new file mode 100644
index 00000000000..235e8645aa8
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/MonitorResource.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.config;
+
+import static java.util.Objects.requireNonNull;
+
+import java.net.URI;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
+
+/**
+ * Container for the {@code MonitorResource} element.
+ */
+@Plugin(name = "MonitorResource", category = Core.CATEGORY_NAME, printObject = true)
+public final class MonitorResource {
+
+    private final URI uri;
+
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Builds MonitorResource instances.
+     */
+    public static final class Builder implements org.apache.logging.log4j.core.util.Builder<MonitorResource> {
+
+        @PluginBuilderAttribute
+        @Required(message = "No URI provided")
+        private URI uri;
+
+        public Builder setUri(final URI uri) {
+            this.uri = uri;
+            return this;
+        }
+
+        @Override
+        public MonitorResource build() {
+            return new MonitorResource(uri);
+        }
+    }
+
+    private MonitorResource(final URI uri) {
+        this.uri = requireNonNull(uri, "uri");
+        if (!"file".equals(uri.getScheme())) {
+            final String message =
+                    String.format("Only `file` scheme is supported in monitor resource URIs! Illegal URI: `%s`", uri);
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    @Override
+    public int hashCode() {
+        return uri.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (!(object instanceof MonitorResource)) {
+            return false;
+        }
+        final MonitorResource other = (MonitorResource) object;
+        return this.uri == other.uri;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("MonitorResource{%s}", uri);
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/MonitorResources.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/MonitorResources.java
new file mode 100644
index 00000000000..f7cc5e20260
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/MonitorResources.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.config;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.logging.log4j.core.Core;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+
+/**
+ * Container for the {@code MonitorResources} element.
+ */
+@Plugin(name = "MonitorResources", category = Core.CATEGORY_NAME, printObject = true)
+public final class MonitorResources {
+
+    private final Set<MonitorResource> resources;
+
+    private MonitorResources(final Set<MonitorResource> resources) {
+        this.resources = requireNonNull(resources, "resources");
+    }
+
+    @PluginFactory
+    public static MonitorResources createMonitorResources(
+            @PluginElement("monitorResource") final MonitorResource[] resources) {
+        requireNonNull(resources, "resources");
+        final LinkedHashSet<MonitorResource> distinctResources =
+                Arrays.stream(resources).collect(Collectors.toCollection(LinkedHashSet::new));
+        return new MonitorResources(distinctResources);
+    }
+
+    public Set<MonitorResource> getResources() {
+        return resources;
+    }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
index 3b9fc489614..9fb9a3f5def 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
@@ -61,6 +61,15 @@ public interface ConfigurationBuilder<T extends Configuration> extends Builder<T
      */
     ConfigurationBuilder<T> add(CustomLevelComponentBuilder builder);
 
+    /**
+     * Adds a top level component.
+     * @param builder The ComponentBuilder with all of its attributes and sub components set.
+     * @return this builder instance.
+     */
+    default ConfigurationBuilder<T> addComponent(ComponentBuilder<?> builder) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * Adds a Filter component.
      * @param builder the FilterComponentBuilder with all of its attributes and sub components set.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/package-info.java
index 273906a5d48..6d91c2d89d8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/package-info.java
@@ -20,7 +20,7 @@
  * @since 2.4
  */
 @Export
-@Version("2.20.1")
+@Version("2.25.0")
 package org.apache.logging.log4j.core.config.builder.api;
 
 import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
index f1ec35e06a0..8445dc706a4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
@@ -46,6 +46,8 @@ public class BuiltConfiguration extends AbstractConfiguration {
     private Component propertiesComponent;
     private Component customLevelsComponent;
     private Component scriptsComponent;
+    private Component monitorResourcesComponent;
+    private Component asyncWaitStrategyFactoryComponent;
     private String contentType = "text";
 
     public BuiltConfiguration(
@@ -78,6 +80,14 @@ public BuiltConfiguration(
                     customLevelsComponent = component;
                     break;
                 }
+                case "MonitorResources": {
+                    monitorResourcesComponent = component;
+                    break;
+                }
+                case "AsyncWaitStrategyFactory": {
+                    asyncWaitStrategyFactoryComponent = component;
+                    break;
+                }
             }
         }
         this.rootComponent = rootComponent;
@@ -95,6 +105,13 @@ public void setup() {
         if (customLevelsComponent.getComponents().size() > 0) {
             children.add(convertToNode(rootNode, customLevelsComponent));
         }
+        if (monitorResourcesComponent != null
+                && monitorResourcesComponent.getComponents().size() > 0) {
+            children.add(convertToNode(rootNode, monitorResourcesComponent));
+        }
+        if (asyncWaitStrategyFactoryComponent != null) {
+            children.add(convertToNode(rootNode, asyncWaitStrategyFactoryComponent));
+        }
         children.add(convertToNode(rootNode, loggersComponent));
         children.add(convertToNode(rootNode, appendersComponent));
         if (filtersComponent.getComponents().size() > 0) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
index 633e619b281..bf039a2dafc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
@@ -24,6 +24,7 @@
 import java.lang.reflect.Constructor;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
@@ -136,6 +137,17 @@ public ConfigurationBuilder<T> add(final AppenderComponentBuilder builder) {
         return add(appenders, builder);
     }
 
+    @Override
+    public ConfigurationBuilder<T> addComponent(ComponentBuilder<?> builder) {
+        return add(root, builder);
+    }
+
+    private Optional<Component> getTopLevelComponent(final String pluginType) {
+        return root.getComponents().stream()
+                .filter(component -> component.getPluginType().equals(pluginType))
+                .findAny();
+    }
+
     @Override
     public ConfigurationBuilder<T> add(final CustomLevelComponentBuilder builder) {
         return add(customLevels, builder);
@@ -291,6 +303,15 @@ private void writeXmlConfiguration(final XMLStreamWriter xmlWriter) throws XMLSt
         writeXmlSection(xmlWriter, properties);
         writeXmlSection(xmlWriter, scripts);
         writeXmlSection(xmlWriter, customLevels);
+        Optional<Component> monitorResourcesComponent = getTopLevelComponent("MonitorResources");
+        if (monitorResourcesComponent.isPresent()
+                && !monitorResourcesComponent.get().getComponents().isEmpty()) {
+            writeXmlComponent(xmlWriter, monitorResourcesComponent.get());
+        }
+        Optional<Component> asyncWaitStrategyFactoryComponent = getTopLevelComponent("AsyncWaitStrategyFactory");
+        if (asyncWaitStrategyFactoryComponent.isPresent()) {
+            writeXmlComponent(xmlWriter, asyncWaitStrategyFactoryComponent.get());
+        }
         if (filters.getComponents().size() == 1) {
             writeXmlComponent(xmlWriter, filters.getComponents().get(0));
         } else if (filters.getComponents().size() > 1) {
@@ -337,7 +358,6 @@ private void writeXmlAttributes(final XMLStreamWriter xmlWriter, final Component
         }
     }
 
-    @Override
     public ScriptComponentBuilder newScript(final String name, final String language, final String text) {
         return new DefaultScriptComponentBuilder(this, name, language, text);
     }
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/package-info.java
index c56f92230f3..32a69487d75 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/package-info.java
@@ -20,7 +20,7 @@
  * @since 2.4
  */
 @Export
-@Version("2.20.2")
+@Version("2.25.0")
 package org.apache.logging.log4j.core.config.builder.impl;
 
 import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/package-info.java
index 111d1644f68..3db1c7abd6b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/package-info.java
@@ -18,7 +18,7 @@
  * Configuration of Log4j 2.
  */
 @Export
-@Version("2.24.1")
+@Version("2.25.0")
 package org.apache.logging.log4j.core.config;
 
 import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
index 6dc9fd6957a..e4770a80ab3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
@@ -187,11 +187,30 @@ public PropertiesConfiguration build() {
             builder.add(createRootLogger(props));
         }
 
+        processRemainingProperties(builder, rootProperties);
+
         builder.setLoggerContext(loggerContext);
 
         return builder.build(false);
     }
 
+    private void processRemainingProperties(
+            final ConfigurationBuilder<PropertiesConfiguration> builder, final Properties properties) {
+        while (properties.size() > 0) {
+            final String propertyName =
+                    properties.stringPropertyNames().iterator().next();
+            final int index = propertyName.indexOf('.');
+            if (index > 0) {
+                final String prefix = propertyName.substring(0, index);
+                final Properties componentProperties = PropertiesUtil.extractSubset(properties, prefix);
+                ComponentBuilder<?> componentBuilder = createComponent(builder, prefix, componentProperties);
+                builder.addComponent(componentBuilder);
+            } else {
+                properties.remove(propertyName);
+            }
+        }
+    }
+
     private ScriptComponentBuilder createScript(final Properties properties) {
         final String name = (String) properties.remove("name");
         final String language = (String) properties.remove("language");
@@ -332,12 +351,17 @@ private LayoutComponentBuilder createLayout(final String appenderName, final Pro
 
     private static <B extends ComponentBuilder<B>> ComponentBuilder<B> createComponent(
             final ComponentBuilder<?> parent, final String key, final Properties properties) {
+        return createComponent(parent.getBuilder(), key, properties);
+    }
+
+    private static <B extends ComponentBuilder<B>> ComponentBuilder<B> createComponent(
+            final ConfigurationBuilder<?> parentBuilder, final String key, final Properties properties) {
         final String name = (String) properties.remove(CONFIG_NAME);
         final String type = (String) properties.remove(CONFIG_TYPE);
         if (Strings.isEmpty(type)) {
             throw new ConfigurationException("No type attribute provided for component " + key);
         }
-        final ComponentBuilder<B> componentBuilder = parent.getBuilder().newComponent(name, type);
+        final ComponentBuilder<B> componentBuilder = parentBuilder.newComponent(name, type);
         return processRemainingProperties(componentBuilder, properties);
     }
 
diff --git a/src/changelog/.2.x.x/3074_monitor_additional_files.xml b/src/changelog/.2.x.x/3074_monitor_additional_files.xml
new file mode 100644
index 00000000000..c32545a602a
--- /dev/null
+++ b/src/changelog/.2.x.x/3074_monitor_additional_files.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns="https://logging.apache.org/xml/ns"
+       xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+       type="added">
+  <issue id="3074" link="https://github.com/apache/logging-log4j2/issues/3074"/>
+  <issue id="3501" link="https://github.com/apache/logging-log4j2/pull/3501"/>
+  <description format="asciidoc">Add `MonitorResource` configuration option to support the monitoring of external files in addition to the configuration file itself.</description>
+</entry>
diff --git a/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.json b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.json
new file mode 100644
index 00000000000..26c566af41b
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.json
@@ -0,0 +1,15 @@
+{
+  "Configuration": {
+    "monitorInterval": "30",
+    "MonitorResources": {
+      "MonitorResource": [
+        {
+          "uri": "file://path/to/external-file-1.txt"
+        },
+        {
+          "uri": "file://path/to/external-file-2.txt"
+        }
+      ]
+    }
+  }
+}
diff --git a/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.properties b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.properties
new file mode 100644
index 00000000000..dd772d9ff10
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.properties
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+monitorInterval = 30
+monitorResources.type = MonitorResources
+monitorResources.0.type = MonitorResource
+monitorResources.0.uri = file://path/to/external-file-1.txt
+monitorResources.1.type = MonitorResource
+monitorResources.1.uri = file://path/to/external-file-2.txt
diff --git a/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.xml b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.xml
new file mode 100644
index 00000000000..1529167d56f
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to you under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd"
+               monitorInterval="30">
+  <MonitorResources>
+    <MonitorResource uri="file://path/to/external-file-1.txt"/>
+    <MonitorResource uri="file://path/to/external-file-2.txt"/>
+  </MonitorResources>
+</Configuration>
diff --git a/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.yaml b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.yaml
new file mode 100644
index 00000000000..11f804108b7
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/configuration/monitor-resources.yaml
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+Configuration:
+  monitorInterval: '30'
+  MonitorResources:
+    MonitorResource:
+      - uri: "file://path/to/external-file-1.txt"
+      - uri: "file://path/to/external-file-2.txt"
diff --git a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc
index 7a0e738e41c..d7f90e6c209 100644
--- a/src/site/antora/modules/ROOT/pages/manual/configuration.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/configuration.adoc
@@ -988,6 +988,65 @@ include::example$manual/configuration/routing.properties[tag=appender]
 Therefore, the dollar `$` sign needs to be escaped.
 <2> All the attributes of children of the `Route` element have a **deferred** evaluation. Therefore, they need only one `$` sign.
 
+[#monitorResources]
+== Monitor Resources
+
+Log4j can be configured to poll for changes to resources (in addition to the configuration file) using the `MonitorResources` element of the configuration.
+If a change is detected in any of the specified resources, Log4j automatically reconfigures the logger context.
+This feature helps with monitoring external resources (e.g., TLS certificates) that the configuration is dependent on.
+
+The polling interval is determined by the value of the <<configuration-attribute-monitorInterval>> attribute.
+If set to 0, polling is disabled.
+See <<configuration-attribute-monitorInterval>> for further details.
+
+A configuration can have either zero or one `MonitorResources` element at its root.
+`MonitorResources` can have zero or more `MonitorResource` elements, which can be configured following attributes:
+
+.`MonitorResource` configuration attributes
+[cols="1m,1,4"]
+|===
+| Attribute | Type | Description
+
+| `uri`
+| URI
+a| A https://docs.oracle.com/javase/{java-target-version}/docs/api/java/net/URI.html[`java.net.URI`] reference to the external resource.
+Note that only URIs of scheme `file` are accepted.
+|===
+
+See example below:
+
+.`MonitorResources` configuration example
+[tabs]
+====
+XML::
++
+[source,xml]
+----
+include::example$manual/configuration/monitor-resources.xml[lines=18..]
+----
+
+JSON::
++
+[source,json]
+----
+include::example$manual/configuration/monitor-resources.json[]
+----
+
+YAML::
++
+[source,yaml]
+----
+include::example$manual/configuration/monitor-resources.yaml[lines=17..]
+----
+
+Properties::
++
+[source,properties]
+----
+include::example$manual/configuration/monitor-resources.properties[lines=18..]
+----
+====
+
 [id=arbiters]
 == [[Arbiters]] Arbiters