diff --git a/server/src/main/java/org/opensearch/LegacyESVersion.java b/server/src/main/java/org/opensearch/LegacyESVersion.java
index e535d209e59..ab1b4400906 100644
--- a/server/src/main/java/org/opensearch/LegacyESVersion.java
+++ b/server/src/main/java/org/opensearch/LegacyESVersion.java
@@ -167,7 +167,7 @@ public class LegacyESVersion extends Version {
                             final int minor = Integer.valueOf(fields[2]) * 10000;
                             final int revision = Integer.valueOf(fields[3]) * 100;
                             final int expectedId;
-                            if (fields[1].equals("1")) {
+                            if (major > 0 && major < 6000000) {
                                 expectedId = 0x08000000 ^ (major + minor + revision + 99);
                             } else {
                                 expectedId = (major + minor + revision + 99);
diff --git a/server/src/main/java/org/opensearch/Version.java b/server/src/main/java/org/opensearch/Version.java
index 142fabf5ad0..999c39cabbc 100644
--- a/server/src/main/java/org/opensearch/Version.java
+++ b/server/src/main/java/org/opensearch/Version.java
@@ -238,8 +238,8 @@ public class Version implements Comparable<Version>, ToXContentFragment {
 
     // LegacyESVersion major 7 is equivalent to Version major 1
     public int compareMajor(Version other) {
-        int m = major == 1 ? 7 : major;
-        int om = other.major == 1 ? 7 : other.major;
+        int m = major == 1 ? 7 : major == 2 ? 8 : major;
+        int om = other.major == 1 ? 7 : other.major == 2 ? 8 : other.major;
         return Integer.compare(m, om);
     }
 
@@ -293,6 +293,8 @@ public class Version implements Comparable<Version>, ToXContentFragment {
         } else if (major == 6) {
             // force the minimum compatibility for version 6 to 5.6 since we don't reference version 5 anymore
             return Version.fromId(5060099);
+        } else if (major == 2) {
+            return LegacyESVersion.V_7_10_0;
         } else if (major >= 7) {
             // all major versions from 7 onwards are compatible with last minor series of the previous major
             Version bwcVersion = null;
@@ -339,6 +341,8 @@ public class Version implements Comparable<Version>, ToXContentFragment {
             bwcMajor = 2; // we jumped from 2 to 5
         } else if (major == 7 || major == 1) {
             return LegacyESVersion.V_6_0_0_beta1;
+        } else if (major == 2) {
+            return LegacyESVersion.V_7_0_0;
         } else {
             bwcMajor = major - 1;
         }
@@ -354,8 +358,20 @@ public class Version implements Comparable<Version>, ToXContentFragment {
             && version.onOrAfter(minimumCompatibilityVersion());
 
         // OpenSearch version 1 is the functional equivalent of predecessor version 7
-        int a = major == 1 ? 7 : major;
-        int b = version.major == 1 ? 7 : version.major;
+        // OpenSearch version 2 is the functional equivalent of predecessor unreleased version "8"
+        // todo refactor this logic after removing deprecated features
+        int a = major;
+        if (major == 1) {
+            a = 7;
+        } else if (major == 2) {
+            a = 8;
+        }
+        int b = version.major;
+        if (version.major == 1) {
+            b = 7;
+        } else if (version.major == 2) {
+            b = 8;
+        }
 
         assert compatible == false || Math.max(a, b) - Math.min(a, b) <= 1;
         return compatible;
diff --git a/server/src/main/java/org/opensearch/cluster/coordination/JoinTaskExecutor.java b/server/src/main/java/org/opensearch/cluster/coordination/JoinTaskExecutor.java
index ac725e613e0..7cf8caf22bc 100644
--- a/server/src/main/java/org/opensearch/cluster/coordination/JoinTaskExecutor.java
+++ b/server/src/main/java/org/opensearch/cluster/coordination/JoinTaskExecutor.java
@@ -367,9 +367,8 @@ public class JoinTaskExecutor implements ClusterStateTaskExecutor<JoinTaskExecut
      * version mode
      **/
     public static void ensureMajorVersionBarrier(Version joiningNodeVersion, Version minClusterNodeVersion) {
-        final byte jnMajor = joiningNodeVersion.major == 1 ? 7 : joiningNodeVersion.major;
         final byte clusterMajor = minClusterNodeVersion.major == 1? 7: minClusterNodeVersion.major;
-        if (jnMajor < clusterMajor) {
+        if (joiningNodeVersion.compareMajor(minClusterNodeVersion) < 0) {
             throw new IllegalStateException("node version [" + joiningNodeVersion + "] is not supported. " +
                 "All nodes in the cluster are of a higher major [" + clusterMajor + "].");
         }
diff --git a/server/src/test/java/org/opensearch/VersionTests.java b/server/src/test/java/org/opensearch/VersionTests.java
index 36bdbd2e1b7..6d8f774fa3f 100644
--- a/server/src/test/java/org/opensearch/VersionTests.java
+++ b/server/src/test/java/org/opensearch/VersionTests.java
@@ -211,6 +211,48 @@ public class VersionTests extends OpenSearchTestCase {
         assertEquals(0, LegacyESVersion.V_7_0_0.minimumCompatibilityVersion().revision);
     }
 
+    /** test opensearch min wire compatibility */
+    public void testOpenSearchMinCompatVersion() {
+        Version opensearchVersion = VersionUtils.randomOpenSearchVersion(random());
+        // opensearch 1.x minCompat is Legacy 6.8.0
+        // opensearch 2.x minCompat is Legacy 7.10.0
+        // opensearch 3.x minCompat is 1.{last minor version}.0
+        // until 3.0 is staged the following line will only return legacy versions
+        List<Version> candidates = opensearchVersion.major >= 3 ? VersionUtils.allOpenSearchVersions() : VersionUtils.allLegacyVersions();
+        int opensearchMajor = opensearchVersion.major;
+        int major = opensearchMajor - 1;
+        if (opensearchMajor == 1) {
+            major = 7;
+        } else if (opensearchMajor == 2) {
+            major = 8;
+        }
+        assertEquals(VersionUtils.lastFirstReleasedMinorFromMajor(candidates, major - 1),
+            opensearchVersion.minimumCompatibilityVersion());
+    }
+
+    /** test opensearch min index compatibility */
+    public void testOpenSearchMinIndexCompatVersion() {
+        Version opensearchVersion = VersionUtils.randomOpenSearchVersion(random());
+        // opensearch 1.x minIndexCompat is Legacy 6.8.0
+        // opensearch 2.x minCompat is Legacy 7.10.0
+        // opensearch 3.x minCompat is 1.{last minor version}.0
+        // until 3.0 is staged the following line will only return legacy versions
+        List<Version> candidates = opensearchVersion.major >= 3 ? VersionUtils.allOpenSearchVersions() : VersionUtils.allLegacyVersions();
+        int opensearchMajor = opensearchVersion.major;
+        int major = opensearchMajor - 1;
+        if (opensearchMajor == 1) {
+            major = 7;
+        } else if (opensearchMajor == 2) {
+            major = 8;
+        }
+        Version expected = VersionUtils.getFirstVersionOfMajor(candidates, major - 1);
+        Version actual = opensearchVersion.minimumIndexCompatibilityVersion();
+        // since some legacy versions still support build (alpha, beta, RC) we check major minor revision only
+        assertEquals(expected.major, actual.major);
+        assertEquals(expected.minor, actual.minor);
+        assertEquals(expected.revision, actual.revision);
+    }
+
     public void testToString() {
         // with 2.0.beta we lowercase
         assertEquals("2.0.0-beta1", LegacyESVersion.fromString("2.0.0-beta1").toString());
diff --git a/server/src/test/java/org/opensearch/cluster/coordination/JoinTaskExecutorTests.java b/server/src/test/java/org/opensearch/cluster/coordination/JoinTaskExecutorTests.java
index a7998d95a52..a24bed1c762 100644
--- a/server/src/test/java/org/opensearch/cluster/coordination/JoinTaskExecutorTests.java
+++ b/server/src/test/java/org/opensearch/cluster/coordination/JoinTaskExecutorTests.java
@@ -88,8 +88,7 @@ public class JoinTaskExecutorTests extends OpenSearchTestCase {
         Settings.builder().build();
         Metadata.Builder metaBuilder = Metadata.builder();
         IndexMetadata indexMetadata = IndexMetadata.builder("test")
-            .settings(settings(VersionUtils.getPreviousVersion(Version.CURRENT
-                .minimumIndexCompatibilityVersion())))
+            .settings(settings(Version.fromString("5.8.0")))
             .numberOfShards(1)
             .numberOfReplicas(1).build();
         metaBuilder.put(indexMetadata, false);
diff --git a/test/framework/src/main/java/org/opensearch/test/VersionUtils.java b/test/framework/src/main/java/org/opensearch/test/VersionUtils.java
index 747190cbd5b..efeae6c6909 100644
--- a/test/framework/src/main/java/org/opensearch/test/VersionUtils.java
+++ b/test/framework/src/main/java/org/opensearch/test/VersionUtils.java
@@ -39,6 +39,7 @@ import org.opensearch.common.collect.Tuple;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -149,6 +150,8 @@ public class VersionUtils {
     private static final List<Version> RELEASED_VERSIONS;
     private static final List<Version> UNRELEASED_VERSIONS;
     private static final List<Version> ALL_VERSIONS;
+    private static final List<Version> ALL_OPENSEARCH_VERSIONS;
+    private static final List<Version> ALL_LEGACY_VERSIONS;
 
     static {
         Tuple<List<Version>, List<Version>> versions = resolveReleasedVersions(Version.CURRENT, LegacyESVersion.class);
@@ -159,6 +162,9 @@ public class VersionUtils {
         allVersions.addAll(UNRELEASED_VERSIONS);
         Collections.sort(allVersions);
         ALL_VERSIONS = Collections.unmodifiableList(allVersions);
+        // @todo remove this when legacy support is no longer needed
+        ALL_OPENSEARCH_VERSIONS = ALL_VERSIONS.stream().filter(v -> v.major < 6).collect(Collectors.toList());
+        ALL_LEGACY_VERSIONS = ALL_VERSIONS.stream().filter(v -> v.major >= 6).collect(Collectors.toList());
     }
 
     /**
@@ -182,6 +188,16 @@ public class VersionUtils {
         return ALL_VERSIONS;
     }
 
+    /** Returns an immutable, sorted list containing all opensearch versions; released and unreleased */
+    public static List<Version> allOpenSearchVersions() {
+        return ALL_OPENSEARCH_VERSIONS;
+    }
+
+    /** Returns an immutable, sorted list containing all legacy versions; released and unreleased */
+    public static List<Version> allLegacyVersions() {
+        return ALL_LEGACY_VERSIONS;
+    }
+
     /**
      * Get the released version before {@code version}.
      */
@@ -224,11 +240,35 @@ public class VersionUtils {
         return RELEASED_VERSIONS.get(0);
     }
 
+    public static Version getFirstVersionOfMajor(List<Version> versions, int major) {
+        Map<Integer, List<Version>> majorVersions = versions.stream().collect(Collectors.groupingBy(v -> (int)v.major));
+        return majorVersions.get(major).get(0);
+    }
+
     /** Returns a random {@link Version} from all available versions. */
     public static Version randomVersion(Random random) {
         return ALL_VERSIONS.get(random.nextInt(ALL_VERSIONS.size()));
     }
 
+    /**
+     * Return a random {@link Version} from all available opensearch versions.
+     **/
+    public static Version randomOpenSearchVersion(Random random) {
+        return ALL_OPENSEARCH_VERSIONS.get(random.nextInt(ALL_OPENSEARCH_VERSIONS.size()));
+    }
+
+    /** Returns the first released (e.g., patch version 0) {@link Version} of the last minor from the requested major version
+     *  e.g., for version 1.0.0 this would be legacy version (7.10.0); the first release (patch 0), of the last
+     *  minor (for 7.x that is minor version 10) for the desired major version (7)
+     **/
+    public static Version lastFirstReleasedMinorFromMajor(List<Version> allVersions, int major) {
+        Map<Integer, List<Version>> majorVersions = allVersions.stream().collect(Collectors.groupingBy(v -> (int)v.major));
+        Map<Integer, List<Version>> groupedByMinor = majorVersions.get(major).stream().collect(
+            Collectors.groupingBy(v -> (int)v.minor));
+        List<Version> candidates = Collections.max(groupedByMinor.entrySet(), Comparator.comparing(Map.Entry::getKey)).getValue();
+        return candidates.get(0);
+    }
+
     /** Returns a random {@link Version} from all available versions, that is compatible with the given version. */
     public static Version randomCompatibleVersion(Random random, Version version) {
         final List<Version> compatible = ALL_VERSIONS.stream().filter(version::isCompatible).collect(Collectors.toList());