diff --git a/.github/workflows/build-install.yaml b/.github/workflows/build-install.yaml
index fff9fd0f22..24168621c6 100644
--- a/.github/workflows/build-install.yaml
+++ b/.github/workflows/build-install.yaml
@@ -120,3 +120,28 @@ jobs:
       - name: 'Run installed osc'
         run: |
             osc --help
+
+  virtualenv:
+    name: 'virtualenv install test'
+    runs-on: 'ubuntu-latest'
+    strategy:
+      fail-fast: false
+
+    steps:
+      - name: 'Install packages'
+        run: |
+            sudo apt-get -y update
+            sudo apt-get -y --no-install-recommends install git python3-pip python3-rpm python3-virtualenv
+
+      - uses: actions/checkout@v3
+
+      - name: 'Initialize virtualenv'
+        run: |
+            python3 -m venv .env3
+            source .env3/bin/activate
+            pip3 install .
+
+      - name: 'Run installed osc'
+        run: |
+            source .env3/bin/activate
+            osc --help
diff --git a/doc/plugins/index.rst b/doc/plugins/index.rst
index 28f3459eed..90299d380c 100644
--- a/doc/plugins/index.rst
+++ b/doc/plugins/index.rst
@@ -5,6 +5,9 @@ Extending osc with plugins
 .. note::
     New in osc 1.1.0
 
+.. warning::
+    Plugins are currently NOT supported in virtualenv.
+
 
 This is a simple tutorial.
 More details can be found in the :py:class:`osc.commandline.OscCommand` reference.
diff --git a/osc/_private/common.py b/osc/_private/common.py
index 6313060a38..1f3623aad1 100644
--- a/osc/_private/common.py
+++ b/osc/_private/common.py
@@ -17,6 +17,9 @@ def print_msg(*args, print_to="debug"):
     elif print_to == "stdout":
         # print the message to stdout
         print(*args)
+    elif print_to == "stderr":
+        # print the message to stderr
+        print(*args, file=sys.stderr)
     else:
         raise ValueError(f"Invalid value of the 'print_to' option: {print_to}")
 
diff --git a/osc/commandline.py b/osc/commandline.py
index f406769ec6..8c2b399d02 100644
--- a/osc/commandline.py
+++ b/osc/commandline.py
@@ -40,6 +40,10 @@
 from .util.helper import _html_escape, format_table
 
 
+# python3.6 requires reading sys.real_prefix to detect virtualenv
+IN_VENV = getattr(sys, "real_prefix", sys.base_prefix) != sys.prefix
+
+
 class Command:
     #: Name of the command as used in the argument parser.
     name: str = None
@@ -262,6 +266,9 @@ def load_command(self, cls, module_prefix):
         return cmd
 
     def load_commands(self):
+        if IN_VENV:
+            _private.print_msg("Running in virtual environment, skipping loading plugins installed outside the virtual environment.", print_to="stderr")
+
         for module_prefix, module_path in self.MODULES:
             module_path = os.path.expanduser(module_path)
 
@@ -317,12 +324,16 @@ class OscMainCommand(MainCommand):
 
     MODULES = (
         ("osc.commands", osc_commands.__path__[0]),
-        ("osc.commands.usr_lib", "/usr/lib/osc-plugins"),
-        ("osc.commands.usr_local_lib", "/usr/local/lib/osc-plugins"),
-        ("osc.commands.home_local_lib", "~/.local/lib/osc-plugins"),
-        ("osc.commands.home", "~/.osc-plugins"),
     )
 
+    if not IN_VENV:
+        MODULES += (
+            ("osc.commands.usr_lib", "/usr/lib/osc-plugins"),
+            ("osc.commands.usr_local_lib", "/usr/local/lib/osc-plugins"),
+            ("osc.commands.home_local_lib", "~/.local/lib/osc-plugins"),
+            ("osc.commands.home", "~/.osc-plugins"),
+        )
+
     def __init__(self):
         super().__init__()
         self.args = None
@@ -10056,6 +10067,10 @@ def do_comment(self, subcmd, opts, *args):
             print(result)
 
     def _load_plugins(self):
+        if IN_VENV:
+            _private.print_msg("Running in virtual environment, skipping loading legacy plugins.", print_to="stderr")
+            return
+
         plugin_dirs = [
             '/usr/lib/osc-plugins',
             '/usr/local/lib/osc-plugins',