diff --git a/CMakeLists.txt b/CMakeLists.txt
index d0b2557078..a1e8a38f64 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,10 @@ set(YDB_SDK_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(YDB_SDK_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 set(YDB-CPP-SDK_AVAILABLE_COMPONENTS "" CACHE INTERNAL "")
 set(YDB-CPP-SDK_COMPONENT_TARGETS "" CACHE INTERNAL "")
-file(READ "src/client/resources/ydb_sdk_version.txt" YDB_SDK_VERSION)
+file(READ "src/version.h" YDB_SDK_VERSION_FILE_RAW)
+string(REGEX MATCH "YDB_SDK_VERSION = \"([0-9]+\\.[0-9]+\\.[0-9]+)\"" _ ${YDB_SDK_VERSION_FILE_RAW})
+set(YDB_SDK_VERSION ${CMAKE_MATCH_1})
+message(STATUS "YDB ะก++ SDK version: ${YDB_SDK_VERSION}")
 
 #[=============================================================================[
   NOTE: if `ccache` is used with the environment variable `CCACHE_BASEDIR`,
diff --git a/examples/secondary_index/secondary_index_list.cpp b/examples/secondary_index/secondary_index_list.cpp
index 59e127d8ba..1946e67dcf 100644
--- a/examples/secondary_index/secondary_index_list.cpp
+++ b/examples/secondary_index/secondary_index_list.cpp
@@ -246,7 +246,7 @@ int RunListSeries(TDriver& driver, const std::string& prefix, int argc, char** a
     uint64_t lastSeriesId = -1;
     uint64_t lastViews = -1;
 
-    opts.AddLongOption("by-views", "Sort by views").NoArgument().SetFlag(&byViews);
+    opts.AddLongOption("by-views", "Sort by views").StoreTrue(&byViews);
     opts.AddLongOption("limit", "Maximum number of rows").Optional().RequiredArgument("NUM")
         .StoreResult(&limit);
     opts.AddLongOption("last-id", "Resume from this last series id").Optional().RequiredArgument("NUM")
diff --git a/include/ydb-cpp-sdk/client/coordination/coordination.h b/include/ydb-cpp-sdk/client/coordination/coordination.h
index d1893ee6ff..4b46428ca9 100644
--- a/include/ydb-cpp-sdk/client/coordination/coordination.h
+++ b/include/ydb-cpp-sdk/client/coordination/coordination.h
@@ -198,7 +198,9 @@ struct TCreateNodeSettings : public TNodeSettings<TCreateNodeSettings> {
     TCreateNodeSettings(const Ydb::Coordination::Config& config);
 };
 struct TAlterNodeSettings : public TNodeSettings<TAlterNodeSettings> { };
-struct TDropNodeSettings : public TOperationRequestSettings<TDropNodeSettings> { };
+struct TDropNodeSettings : public TOperationRequestSettings<TDropNodeSettings> {
+    using TOperationRequestSettings<TDropNodeSettings>::TOperationRequestSettings;
+};
 struct TDescribeNodeSettings : public TOperationRequestSettings<TDescribeNodeSettings> { };
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/ydb-cpp-sdk/client/draft/ydb_replication.h b/include/ydb-cpp-sdk/client/draft/ydb_replication.h
index ba8a872bfb..09eb0725d8 100644
--- a/include/ydb-cpp-sdk/client/draft/ydb_replication.h
+++ b/include/ydb-cpp-sdk/client/draft/ydb_replication.h
@@ -100,6 +100,8 @@ class TRunningState {
 
 struct TDoneState {};
 
+struct TPausedState {};
+
 class TErrorState {
     class TImpl;
 
@@ -131,6 +133,7 @@ class TReplicationDescription {
         Running,
         Error,
         Done,
+        Paused,
     };
 
     explicit TReplicationDescription(const Ydb::Replication::DescribeReplicationResult& desc);
@@ -145,6 +148,7 @@ class TReplicationDescription {
     const TRunningState& GetRunningState() const;
     const TErrorState& GetErrorState() const;
     const TDoneState& GetDoneState() const;
+    const TPausedState& GetPausedState() const;
 
 private:
     TConnectionParams ConnectionParams_;
@@ -158,7 +162,8 @@ class TReplicationDescription {
     std::variant<
         TRunningState,
         TErrorState,
-        TDoneState
+        TDoneState,
+        TPausedState
     > State_;
 };
 
diff --git a/include/ydb-cpp-sdk/client/extensions/solomon_stats/README.md b/include/ydb-cpp-sdk/client/extensions/solomon_stats/README.md
index b4e2ebb179..eb60778b02 100644
--- a/include/ydb-cpp-sdk/client/extensions/solomon_stats/README.md
+++ b/include/ydb-cpp-sdk/client/extensions/solomon_stats/README.md
@@ -32,8 +32,8 @@ After creating NYdb::TDriver you need to add Solomon Monitoring extension. If yo
 > **Important**: you must plug in monitoring before driver creation.
 
 ```cl
-#include <src/client/ydb_driver/driver.h>
-#include <src/client/extensions/solomon_stats/pull_client.h>
+#include <ydb-cpp-sdk/client/driver/driver.h>
+#include <ydb-cpp-sdk/client/extensions/solomon_stats/pull_client.h>
 
 ...
 
@@ -65,7 +65,7 @@ Implementing NMonitoring::IMetricRegistry provides more flexibility. You can del
 
 Select a method which is right for you:
 ```cl
-#include <src/client/extensions/solomon_stats/pull_connector.h>
+#include <ydb-cpp-sdk/client/extensions/solomon_stats/pull_connector.h>
 
 ...
 
diff --git a/include/ydb-cpp-sdk/client/federated_topic/federated_topic.h b/include/ydb-cpp-sdk/client/federated_topic/federated_topic.h
index e1fff416ab..45e9809b63 100644
--- a/include/ydb-cpp-sdk/client/federated_topic/federated_topic.h
+++ b/include/ydb-cpp-sdk/client/federated_topic/federated_topic.h
@@ -15,6 +15,8 @@ using TDbInfo = Ydb::FederationDiscovery::DatabaseInfo;
 
 using TSessionClosedEvent = NTopic::TSessionClosedEvent;
 
+using TAsyncDescribeTopicResult = NTopic::TAsyncDescribeTopicResult;
+
 //! Federated partition session.
 struct TFederatedPartitionSession : public TThrRefBase, public TPrintable<TFederatedPartitionSession> {
     using TPtr = TIntrusivePtr<TFederatedPartitionSession>;
@@ -516,6 +518,32 @@ class TFederatedTopicClient {
     // std::shared_ptr<NTopic::ISimpleBlockingWriteSession> CreateSimpleBlockingWriteSession(const TFederatedWriteSessionSettings& settings);
     std::shared_ptr<NTopic::IWriteSession> CreateWriteSession(const TFederatedWriteSessionSettings& settings);
 
+    struct TClusterInfo {
+        enum class EStatus : int {
+            STATUS_UNSPECIFIED,
+            AVAILABLE,
+            READ_ONLY,
+            UNAVAILABLE,
+        };
+        std::string Name;
+        std::string Endpoint;
+        std::string Path;
+        EStatus Status;
+        // TODO: Id, Weight, ...?
+        //! Replaces Endpoint and Database for federated clusters
+        void AdjustTopicClientSettings(NTopic::TTopicClientSettings& settings) const;
+        //! Prepend Database for federated clusters
+        void AdjustTopicPath(std::string& path) const;
+        //! Usable for at least read operations
+        bool IsAvailableForRead() const;
+        bool IsAvailableForWrite() const;
+    };
+
+    //! Discover all clusters for federated topic.
+    // Will return single cluster with empty name for non-federated clusters.
+    // May return empty list if FederatedTopicClient was destroyed when future fired.
+    NThreading::TFuture<std::vector<TClusterInfo>> GetAllClusterInfo();
+
 protected:
     void OverrideCodec(NTopic::ECodec codecId, std::unique_ptr<NTopic::ICodec>&& codecImpl);
 
diff --git a/include/ydb-cpp-sdk/client/table/table.h b/include/ydb-cpp-sdk/client/table/table.h
index e26c6ec67f..5ca46f7c82 100644
--- a/include/ydb-cpp-sdk/client/table/table.h
+++ b/include/ydb-cpp-sdk/client/table/table.h
@@ -1955,6 +1955,7 @@ class TDataQuery {
     const std::string& GetId() const;
     const std::optional<std::string>& GetText() const;
     TParamsBuilder GetParamsBuilder() const;
+    std::map<std::string, TType> GetParameterTypes() const;
 
     TAsyncDataQueryResult Execute(const TTxControl& txControl,
         const TExecDataQuerySettings& settings = TExecDataQuerySettings());
diff --git a/include/ydb-cpp-sdk/client/types/ydb.h b/include/ydb-cpp-sdk/client/types/ydb.h
index 3957f1fedc..3ae912fadf 100644
--- a/include/ydb-cpp-sdk/client/types/ydb.h
+++ b/include/ydb-cpp-sdk/client/types/ydb.h
@@ -16,7 +16,10 @@ enum class EDiscoveryMode {
     //! we got endpoint list. The error will be returned if the endpoint list
     //! is empty and discovery failed
     //! This method is a bit more "user friendly" but can produce additional hidden latency
-    Async
+    Async,
+    //! Do not perform discovery.
+    //! This option disables database discovery and allow to use user provided endpoint for grpc connections
+    Off
 };
 
 enum class EBalancingPolicy {
diff --git a/include/ydb-cpp-sdk/type_switcher.h b/include/ydb-cpp-sdk/type_switcher.h
index d0efd61d7d..f7c189adc5 100644
--- a/include/ydb-cpp-sdk/type_switcher.h
+++ b/include/ydb-cpp-sdk/type_switcher.h
@@ -3,7 +3,7 @@
 #include <string>
 
 namespace NYdb {
-inline namespace Dev {
+inline namespace V3 {
 
 using TStringType = std::string;
 
diff --git a/src/api/protos/draft/fq.proto b/src/api/protos/draft/fq.proto
index 16103753b9..84177a909b 100644
--- a/src/api/protos/draft/fq.proto
+++ b/src/api/protos/draft/fq.proto
@@ -431,11 +431,16 @@ message ServiceAccountAuth {
     string id = 1 [(Ydb.length).le = 1024];
 }
 
+message TokenAuth {
+    string token = 1 [(Ydb.length).le = 1024, (Ydb.sensitive) = true];
+}
+
 message IamAuth {
     oneof identity {
         CurrentIAMTokenAuth current_iam = 1;
         ServiceAccountAuth service_account = 2;
         NoneAuth none = 3;
+        TokenAuth token = 4;
     }
 }
 
diff --git a/src/api/protos/draft/ydb_maintenance.proto b/src/api/protos/draft/ydb_maintenance.proto
index d6c754d807..39b7c67d32 100644
--- a/src/api/protos/draft/ydb_maintenance.proto
+++ b/src/api/protos/draft/ydb_maintenance.proto
@@ -96,9 +96,24 @@ message MaintenanceTaskOptions {
 
 // Used to describe the scope of a single action.
 message ActionScope {
+    message PDiskId {
+        uint32 node_id = 1;
+        uint32 pdisk_id = 2;
+    }
+    message PDiskLocation {
+        string host = 1 [(length).le = 255];
+        string path = 2 [(length).le = 255];
+    }
+    message PDisk {
+        oneof pdisk {
+            PDiskId pdisk_id = 1;
+            PDiskLocation pdisk_location = 2;
+        }
+    }
     oneof scope {
         uint32 node_id = 1;
         string host = 2 [(length).le = 255];
+        PDisk pdisk = 3;
     }
 }
 
@@ -182,6 +197,10 @@ message MaintenanceTaskResult {
     repeated ActionGroupStates action_group_states = 2;
     // Try again after this deadline. Specified if there are no performed actions.
     optional google.protobuf.Timestamp retry_after = 3;
+    // The time when the mainteance task was created.
+    google.protobuf.Timestamp create_time = 4;
+    // The last time when the mainteance task was refreshed. Initially equals to create_time.
+    google.protobuf.Timestamp last_refresh_time = 5;
 }
 
 message MaintenanceTaskResponse {
@@ -197,6 +216,10 @@ message GetMaintenanceTaskRequest {
 message GetMaintenanceTaskResult {
     MaintenanceTaskOptions task_options = 1;
     repeated ActionGroupStates action_group_states = 2;
+    // The time when the mainteance task was created.
+    google.protobuf.Timestamp create_time = 3;
+    // The last time when the mainteance task was refreshed. Initially equals to create_time.
+    google.protobuf.Timestamp last_refresh_time = 4;
 }
 
 message GetMaintenanceTaskResponse {
diff --git a/src/api/protos/draft/ydb_replication.proto b/src/api/protos/draft/ydb_replication.proto
index 36ff7119a1..4ef82408e6 100644
--- a/src/api/protos/draft/ydb_replication.proto
+++ b/src/api/protos/draft/ydb_replication.proto
@@ -77,6 +77,9 @@ message DescribeReplicationResult {
     message DoneState {
     }
 
+    message PausedState {
+    }
+
     // Description of scheme object.
     Ydb.Scheme.Entry self = 1;
 
@@ -90,6 +93,7 @@ message DescribeReplicationResult {
         RunningState running = 4;
         ErrorState error = 5;
         DoneState done = 6;
+        PausedState paused = 9;
     }
 }
 
diff --git a/src/api/protos/ydb_export.proto b/src/api/protos/ydb_export.proto
index 189c322e03..f8f3a8e7f0 100644
--- a/src/api/protos/ydb_export.proto
+++ b/src/api/protos/ydb_export.proto
@@ -1,6 +1,7 @@
 syntax = "proto3";
 option cc_enable_arenas = true;
 
+import "src/api/protos/annotations/sensitive.proto";
 import "src/api/protos/annotations/validation.proto";
 import "src/api/protos/ydb_operation.proto";
 
@@ -86,15 +87,19 @@ message ExportToS3Settings {
     };
 
     message Item {
-        // Database path to a table to be exported
+        // Database path to a table/directory to be exported
         string source_path = 1 [(required) = true];
 
         /* Tables are exported to one or more S3 objects.
            The object name begins with 'destination_prefix'.
            This prefix will be followed by '/data_PartNumber', where 'PartNumber'
            represents the index of the part, starting at zero.
+           Not required if the default `destination_prefix` is set.
+           If not specified, actual S3 path is the default `destination_prefix` concatenated with:
+            * The object path relative to the global `source_path` for a non-encrypted export
+            * The anonymized path for an encrypted export
         */
-        string destination_prefix = 2 [(required) = true];
+        string destination_prefix = 2;
     }
 
     string endpoint = 1 [(required) = true];
@@ -102,7 +107,7 @@ message ExportToS3Settings {
     string bucket = 3 [(required) = true];
     string access_key = 4 [(required) = true];
     string secret_key = 5 [(required) = true];
-    repeated Item items = 6 [(size).ge = 1];
+    repeated Item items = 6;
     string description = 7 [(length).le = 128];
     uint32 number_of_retries = 8;
     StorageClass storage_class = 9;
@@ -120,6 +125,20 @@ message ExportToS3Settings {
     // details: https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html
     // it is especially useful for custom s3 implementations
     bool disable_virtual_addressing = 12;
+
+    // Database root if not provided.
+    // All object names are calculated and written relative to this path.
+    string source_path = 13;
+
+    // A default S3 path prefix for all export items.
+    // When specified, export writes SchemaMapping file with the list of objects.
+    // Must be provided for an encrypted backup.
+    string destination_prefix = 14;
+
+    // Settings for data encryption.
+    // If encryption_settings field is not specified,
+    // the resulting data will not be encrypted.
+    EncryptionSettings encryption_settings = 15;
 }
 
 message ExportToS3Result {
@@ -141,3 +160,24 @@ message ExportToS3Response {
     // operation.metadata = ExportToS3Metadata
     Ydb.Operations.Operation operation = 1;
 }
+
+// Export encryption settings
+// Don't specify this struct for unencrypted exports
+message EncryptionSettings {
+    // Algorithm for export encryption.
+    // Not required in case of import/list operation.
+    // Currently the following algorithms are supported:
+    //  AES-128-GCM
+    //  AES-256-GCM
+    //  ChaCha20-Poly1305
+    string encryption_algorithm = 1;
+
+    oneof Key {
+        SymmetricKey symmetric_key = 2;
+    }
+
+    message SymmetricKey {
+        // This key will be used for data encryption
+        bytes key = 1 [(Ydb.sensitive) = true];
+    }
+}
diff --git a/src/api/protos/ydb_import.proto b/src/api/protos/ydb_import.proto
index c7f7b586ea..3e21023525 100644
--- a/src/api/protos/ydb_import.proto
+++ b/src/api/protos/ydb_import.proto
@@ -2,6 +2,7 @@ syntax = "proto3";
 option cc_enable_arenas = true;
 
 import "src/api/protos/annotations/validation.proto";
+import "src/api/protos/ydb_export.proto";
 import "src/api/protos/ydb_operation.proto";
 
 import "google/protobuf/timestamp.proto";
@@ -39,17 +40,25 @@ message ImportFromS3Settings {
     }
 
     message Item {
-        /* YDB tables in S3 are stored in one or more objects (see ydb_export.proto).
-           The object name begins with 'source_prefix'.
-           This prefix is followed by:
-             * '/data_PartNumber', where 'PartNumber' represents the index of the part, starting at zero;
-             * '/scheme.pb' - object with information about scheme, indexes, etc;
-             * '/permissions.pb' - object with information about ACL and owner.
-        */
-        string source_prefix = 1 [(required) = true];
-
-        // Database path to a table to import to.
-        string destination_path = 2 [(required) = true];
+        oneof Source {
+            /* YDB database objects in S3 are stored in one or more S3 objects (see ydb_export.proto).
+            The S3 object name begins with a prefix, followed by:
+                * '/data_PartNumber', where 'PartNumber' represents the index of the part, starting at zero;
+                * '/scheme.pb' - object with information about scheme, indexes, etc;
+                * '/permissions.pb' - object with information about ACL and owner.
+            */
+
+            // The S3 object prefix can be either provided explicitly
+            string source_prefix = 1;
+
+            // Or, if the export contains the database objects list, you may specify the database object name, and the S3 prefix will be looked up in the database objects list by the import procedure
+            string source_path = 3;
+        }
+
+        // Database path to a database object to import the item to
+        // Resolved relative to the default destination_path
+        // May be omitted if the item's source_path is specified, in this case will be taken equal to it
+        string destination_path = 2;
     }
 
     string endpoint = 1 [(required) = true];
@@ -57,7 +66,7 @@ message ImportFromS3Settings {
     string bucket = 3 [(required) = true];
     string access_key = 4 [(required) = true];
     string secret_key = 5 [(required) = true];
-    repeated Item items = 6 [(size).ge = 1];
+    repeated Item items = 6; // Empty collection means import of all export objects
     string description = 7 [(length).le = 128];
     uint32 number_of_retries = 8;
 
@@ -76,6 +85,20 @@ message ImportFromS3Settings {
 
     // Skip checksum validation during import
     bool skip_checksum_validation = 12;
+
+    // A default path prefix for all items,
+    // determines that the import works with the list of objects in the SchemaMapping file.
+    // Must be provided to import an encrypted export.
+    string source_prefix = 13;
+
+    // Destination path to restore paths inside database
+    // Default value is database root
+    string destination_path = 14;
+
+    // Settings how data is encrypted.
+    // If encryption_settings field is not specified,
+    // the resulting data is considered not encrypted.
+    Ydb.Export.EncryptionSettings encryption_settings = 15;
 }
 
 message ImportFromS3Result {
diff --git a/src/api/protos/ydb_monitoring.proto b/src/api/protos/ydb_monitoring.proto
index 2e708d4a5b..e012c61b90 100644
--- a/src/api/protos/ydb_monitoring.proto
+++ b/src/api/protos/ydb_monitoring.proto
@@ -29,6 +29,7 @@ message SelfCheckRequest {
     uint32 maximum_level = 4; // maximum level of issues to return
     bool do_not_cache = 5; // by default database health state is taken from metadata cache; this option can be used to force bypassing that cache
     bool merge_records = 6; // combine similar records with similar status, message and level into one issue
+    bool return_hints = 7; // return hints for common problems
 }
 
 message SelfCheckResponse {
@@ -163,10 +164,16 @@ message LocationComputeTablet {
     uint32 count = 3;
 }
 
+message LocationComputeSchema {
+    string type = 1;
+    string path = 2;
+}
+
 message LocationCompute {
     LocationNode node = 1;
     LocationComputePool pool = 2;
     LocationComputeTablet tablet = 3;
+    LocationComputeSchema schema = 4;
 }
 
 message LocationDatabase {
diff --git a/src/api/protos/ydb_scheme.proto b/src/api/protos/ydb_scheme.proto
index 679c95b48a..2b172e9590 100644
--- a/src/api/protos/ydb_scheme.proto
+++ b/src/api/protos/ydb_scheme.proto
@@ -66,6 +66,7 @@ message Entry {
         EXTERNAL_DATA_SOURCE = 19;
         VIEW = 20;
         RESOURCE_POOL = 21;
+        TRANSFER = 23;
     }
 
     // Name of scheme entry (dir2 of /dir1/dir2)
diff --git a/src/client/draft/ydb_replication.cpp b/src/client/draft/ydb_replication.cpp
index c6b2a61adf..d637cb3e7f 100644
--- a/src/client/draft/ydb_replication.cpp
+++ b/src/client/draft/ydb_replication.cpp
@@ -162,6 +162,10 @@ TReplicationDescription::TReplicationDescription(const Ydb::Replication::Describ
         State_ = TDoneState();
         break;
 
+    case Ydb::Replication::DescribeReplicationResult::kPaused:
+        State_ = TPausedState();
+        break;
+
     default:
         break;
     }
@@ -200,6 +204,10 @@ const TDoneState& TReplicationDescription::GetDoneState() const {
     return std::get<TDoneState>(State_);
 }
 
+const TPausedState& TReplicationDescription::GetPausedState() const {
+    return std::get<TPausedState>(State_);
+}
+
 TDescribeReplicationResult::TDescribeReplicationResult(TStatus&& status, Ydb::Replication::DescribeReplicationResult&& desc)
     : NScheme::TDescribePathResult(std::move(status), desc.self())
     , ReplicationDescription_(desc)
diff --git a/src/client/federated_topic/impl/federated_topic.cpp b/src/client/federated_topic/impl/federated_topic.cpp
index ca1a1caa3f..5b0f7f2b19 100644
--- a/src/client/federated_topic/impl/federated_topic.cpp
+++ b/src/client/federated_topic/impl/federated_topic.cpp
@@ -86,4 +86,33 @@ void TFederatedTopicClient::OverrideCodec(NTopic::ECodec codecId, std::unique_pt
     return Impl_->OverrideCodec(codecId, std::move(codecImpl));
 }
 
+NThreading::TFuture<std::vector<TFederatedTopicClient::TClusterInfo>> TFederatedTopicClient::GetAllClusterInfo() {
+    return Impl_->GetAllClusterInfo();
+}
+
+void TFederatedTopicClient::TClusterInfo::AdjustTopicClientSettings(NTopic::TTopicClientSettings& settings) const {
+    if (Name.empty()) {
+        return;
+    }
+    settings.DiscoveryEndpoint(Endpoint);
+    settings.Database(Path);
+}
+
+void TFederatedTopicClient::TClusterInfo::AdjustTopicPath(std::string& path) const {
+    if (Name.empty()) {
+        return;
+    }
+    if (path.empty() || path[0] != '/') {
+        path = Path + '/' + path;
+    }
+}
+
+bool TFederatedTopicClient::TClusterInfo::IsAvailableForRead() const {
+    return Status == TClusterInfo::EStatus::AVAILABLE || Status == TClusterInfo::EStatus::READ_ONLY;
+}
+
+bool TFederatedTopicClient::TClusterInfo::IsAvailableForWrite() const {
+    return Status == TClusterInfo::EStatus::AVAILABLE;
+}
+
 } // namespace NYdb::NFederatedTopic
diff --git a/src/client/federated_topic/impl/federated_topic_impl.cpp b/src/client/federated_topic/impl/federated_topic_impl.cpp
index 4a1384800e..53e4f18204 100644
--- a/src/client/federated_topic/impl/federated_topic_impl.cpp
+++ b/src/client/federated_topic/impl/federated_topic_impl.cpp
@@ -49,6 +49,40 @@ void TFederatedTopicClient::TImpl::InitObserver() {
     }
 }
 
+NThreading::TFuture<std::vector<TFederatedTopicClient::TClusterInfo>> TFederatedTopicClient::TImpl::GetAllClusterInfo() {
+    InitObserver();
+    return Observer->WaitForFirstState().Apply(
+            [weakObserver = std::weak_ptr(Observer)] (const auto& ) {
+                std::vector<TClusterInfo> result;
+                auto observer = weakObserver.lock();
+                if (!observer) {
+                    return result;
+                }
+                auto state = observer->GetState();
+                result.reserve(state->DbInfos.size());
+                for (const auto& db: state->DbInfos) {
+                    auto& dbinfo = result.emplace_back();
+                    switch (db->status()) {
+#define TRANSLATE_STATUS(NAME) \
+                    case TDbInfo::Status::DatabaseInfo_Status_##NAME: \
+                        dbinfo.Status = TClusterInfo::EStatus::NAME; \
+                        break
+                    TRANSLATE_STATUS(STATUS_UNSPECIFIED);
+                    TRANSLATE_STATUS(AVAILABLE);
+                    TRANSLATE_STATUS(READ_ONLY);
+                    TRANSLATE_STATUS(UNAVAILABLE);
+                    default:
+                        Y_ENSURE(false /* impossible status */);
+                    }
+#undef TRANSLATE_STATUS
+                    dbinfo.Name = db->name();
+                    dbinfo.Endpoint = db->endpoint();
+                    dbinfo.Path = db->path();
+                }
+                return result;
+            });
+}
+
 auto TFederatedTopicClient::TImpl::GetSubsessionHandlersExecutor() -> NTopic::IExecutor::TPtr {
     with_lock (Lock) {
         if (!SubsessionHandlersExecutor) {
diff --git a/src/client/federated_topic/impl/federated_topic_impl.h b/src/client/federated_topic/impl/federated_topic_impl.h
index 164dd82cd6..7638904dab 100644
--- a/src/client/federated_topic/impl/federated_topic_impl.h
+++ b/src/client/federated_topic/impl/federated_topic_impl.h
@@ -65,6 +65,8 @@ class TFederatedTopicClient::TImpl {
     std::shared_ptr<NTopic::ISimpleBlockingWriteSession> CreateSimpleBlockingWriteSession(const TFederatedWriteSessionSettings& settings);
     std::shared_ptr<NTopic::IWriteSession> CreateWriteSession(const TFederatedWriteSessionSettings& settings);
 
+    NThreading::TFuture<std::vector<TFederatedTopicClient::TClusterInfo>> GetAllClusterInfo();
+
     std::shared_ptr<TFederatedDbObserver> GetObserver() {
         std::lock_guard guard(Lock);
         return Observer;
diff --git a/src/client/federated_topic/impl/federation_observer.cpp b/src/client/federated_topic/impl/federation_observer.cpp
index 467dabfbbe..9d40845c62 100644
--- a/src/client/federated_topic/impl/federation_observer.cpp
+++ b/src/client/federated_topic/impl/federation_observer.cpp
@@ -197,6 +197,9 @@ IOutputStream& operator<<(IOutputStream& out, TFederatedDbState const& state) {
         }
         out << " ]";
     }
+    if (!state.ControlPlaneEndpoint.empty()) {
+        out << " ControlPlaneEndpoint: " << state.ControlPlaneEndpoint;
+    }
     return out << " }";
 }
 
diff --git a/src/client/iam/common/iam.h b/src/client/iam/common/iam.h
index 22bd10e5fc..140ac966dd 100644
--- a/src/client/iam/common/iam.h
+++ b/src/client/iam/common/iam.h
@@ -126,7 +126,7 @@ class TGrpcIamCredentialsProvider : public ICredentialsProvider {
 
                     RequestInflight_ = false;
                     sleepDuration = std::min(BackoffTimeout_, BACKOFF_MAX);
-                    BackoffTimeout_ *= 2;
+                    BackoffTimeout_ = std::min(BackoffTimeout_ * 2, BACKOFF_MAX);
                 }
 
                 Sleep(sleepDuration);
diff --git a/src/client/impl/ydb_internal/db_driver_state/state.cpp b/src/client/impl/ydb_internal/db_driver_state/state.cpp
index 76f94af60c..c71349bc00 100644
--- a/src/client/impl/ydb_internal/db_driver_state/state.cpp
+++ b/src/client/impl/ydb_internal/db_driver_state/state.cpp
@@ -205,27 +205,32 @@ TDbDriverStatePtr TDbDriverStateTracker::GetDriverState(
                     ? credentialsProviderFactory->CreateProvider(strongState)
                     : CreateInsecureCredentialsProviderFactory()->CreateProvider(strongState));
 
-            DiscoveryClient_->AddPeriodicTask(CreatePeriodicDiscoveryTask(strongState), DISCOVERY_RECHECK_PERIOD);
+            if (discoveryMode != EDiscoveryMode::Off) {
+                DiscoveryClient_->AddPeriodicTask(CreatePeriodicDiscoveryTask(strongState), DISCOVERY_RECHECK_PERIOD);
+            }
             Y_ABORT_UNLESS(States_.emplace(key, strongState).second);
             break;
         }
     }
-    auto updateResult = strongState->EndpointPool.UpdateAsync();
-    if (updateResult.second) {
-        auto cb = [strongState](const NThreading::TFuture<TEndpointUpdateResult>&) {
-            strongState->SignalDiscoveryCompleted();
-        };
-        updateResult.first.Subscribe(cb);
-    }
 
-    if (strongState->DiscoveryMode == EDiscoveryMode::Sync) {
-        const auto& discoveryStatus = updateResult.first.GetValueSync().DiscoveryStatus;
-        // Almost always true, except the situation when the current thread was
-        // preempted just before UpdateAsync call and other one get
-        // state from cache and call UpdateAsync before us.
-        if (Y_LIKELY(updateResult.second)) {
-            std::unique_lock guard(strongState->LastDiscoveryStatusRWLock);
-            strongState->LastDiscoveryStatus = discoveryStatus;
+    if (strongState->DiscoveryMode != EDiscoveryMode::Off) {
+        auto updateResult = strongState->EndpointPool.UpdateAsync();
+        if (updateResult.second) {
+            auto cb = [strongState](const NThreading::TFuture<TEndpointUpdateResult>&) {
+                strongState->SignalDiscoveryCompleted();
+            };
+            updateResult.first.Subscribe(cb);
+        }
+
+        if (strongState->DiscoveryMode == EDiscoveryMode::Sync) {
+            const auto& discoveryStatus = updateResult.first.GetValueSync().DiscoveryStatus;
+            // Almost always true, except the situation when the current thread was
+            // preempted just before UpdateAsync call and other one get
+            // state from cache and call UpdateAsync before us.
+            if (Y_LIKELY(updateResult.second)) {
+                std::unique_lock guard(strongState->LastDiscoveryStatusRWLock);
+                strongState->LastDiscoveryStatus = discoveryStatus;
+            }
         }
     }
 
diff --git a/src/client/impl/ydb_internal/grpc_connections/grpc_connections.h b/src/client/impl/ydb_internal/grpc_connections/grpc_connections.h
index 6d3012900b..db777210ca 100644
--- a/src/client/impl/ydb_internal/grpc_connections/grpc_connections.h
+++ b/src/client/impl/ydb_internal/grpc_connections/grpc_connections.h
@@ -98,20 +98,22 @@ class TGRpcConnectionsImpl
             clientConfig.MaxOutboundMessageSize = MaxOutboundMessageSize_;
         }
 
-        if (std::is_same<TService,Ydb::Discovery::V1::DiscoveryService>()
-            || dbState->Database.empty()
-            || endpointPolicy == TRpcRequestSettings::TEndpointPolicy::UseDiscoveryEndpoint)
-        {
-            SetGrpcKeepAlive(clientConfig, GRPC_KEEP_ALIVE_TIMEOUT_FOR_DISCOVERY, GRpcKeepAlivePermitWithoutCalls_);
-        } else {
-            auto endpoint = dbState->EndpointPool.GetEndpoint(preferredEndpoint, endpointPolicy == TRpcRequestSettings::TEndpointPolicy::UsePreferredEndpointStrictly);
-            if (!endpoint) {
-                return {nullptr, TEndpointKey()};
-            }
-            clientConfig.Locator = endpoint.Endpoint;
-            clientConfig.SslTargetNameOverride = endpoint.SslTargetNameOverride;
-            if (GRpcKeepAliveTimeout_) {
-                SetGrpcKeepAlive(clientConfig, GRpcKeepAliveTimeout_, GRpcKeepAlivePermitWithoutCalls_);
+        if (dbState->DiscoveryMode != EDiscoveryMode::Off) {
+            if (std::is_same<TService,Ydb::Discovery::V1::DiscoveryService>()
+                || dbState->Database.empty()
+                || endpointPolicy == TRpcRequestSettings::TEndpointPolicy::UseDiscoveryEndpoint)
+            {
+                SetGrpcKeepAlive(clientConfig, GRPC_KEEP_ALIVE_TIMEOUT_FOR_DISCOVERY, GRpcKeepAlivePermitWithoutCalls_);
+            } else {
+                auto endpoint = dbState->EndpointPool.GetEndpoint(preferredEndpoint, endpointPolicy == TRpcRequestSettings::TEndpointPolicy::UsePreferredEndpointStrictly);
+                if (!endpoint) {
+                    return {nullptr, TEndpointKey()};
+                }
+                clientConfig.Locator = endpoint.Endpoint;
+                clientConfig.SslTargetNameOverride = endpoint.SslTargetNameOverride;
+                if (GRpcKeepAliveTimeout_) {
+                    SetGrpcKeepAlive(clientConfig, GRpcKeepAliveTimeout_, GRpcKeepAlivePermitWithoutCalls_);
+                }
             }
         }
 
@@ -609,7 +611,17 @@ class TGRpcConnectionsImpl
         TEndpointKey endpoint;
         std::tie(serviceConnection, endpoint) = GetServiceConnection<TService>(dbState, preferredEndpoint, endpointPolicy);
         if (!serviceConnection) {
-            if (dbState->DiscoveryMode == EDiscoveryMode::Sync) {
+            if (dbState->DiscoveryMode == EDiscoveryMode::Off) {
+                TStringStream errString;
+                errString << "No endpoint for database " << dbState->Database;
+                errString << ", cluster endpoint " << dbState->DiscoveryEndpoint;
+                dbState->StatCollector.IncReqFailNoEndpoint();
+                callback(
+                    TPlainStatus(EStatus::UNAVAILABLE, errString.Str()),
+                    TConnection{nullptr},
+                    TEndpointKey{ });
+
+            } else if (dbState->DiscoveryMode == EDiscoveryMode::Sync) {
                 TStringStream errString;
                 errString << "Endpoint list is empty for database " << dbState->Database;
                 errString << ", cluster endpoint " << dbState->DiscoveryEndpoint;
diff --git a/src/client/persqueue_public/ut/read_session_ut.cpp b/src/client/persqueue_public/ut/read_session_ut.cpp
index 8ab0db9712..895a2aa96f 100644
--- a/src/client/persqueue_public/ut/read_session_ut.cpp
+++ b/src/client/persqueue_public/ut/read_session_ut.cpp
@@ -595,7 +595,7 @@ TReadSessionImplTestSetup::TReadSessionImplTestSetup() {
 }
 
 TReadSessionImplTestSetup::~TReadSessionImplTestSetup() noexcept(false) {
-    if (!std::uncaught_exception()) { // Exiting from test successfully. Check additional expectations.
+    if (!std::uncaught_exceptions()) { // Exiting from test successfully. Check additional expectations.
         MockProcessorFactory->Wait();
         MockProcessor->Wait();
 
diff --git a/src/client/resources/CMakeLists.txt b/src/client/resources/CMakeLists.txt
index 3074324f62..24a9f19ac5 100644
--- a/src/client/resources/CMakeLists.txt
+++ b/src/client/resources/CMakeLists.txt
@@ -19,10 +19,8 @@ target_sources(client-resources.global PRIVATE
 resources(client-resources.global
   ${YDB_SDK_BINARY_DIR}/src/client/resources/6ed212bf45019efe2a5e72b6d5ed50fb.cpp
   INPUTS
-  ${YDB_SDK_SOURCE_DIR}/src/client/resources/ydb_sdk_version.txt
   ${YDB_SDK_SOURCE_DIR}/src/client/resources/ydb_root_ca.pem
   KEYS
-  ydb_sdk_version_v3.txt
   ydb_root_ca_v3.pem
 )
 
diff --git a/src/client/resources/ydb_ca.cpp b/src/client/resources/ydb_ca.cpp
index 96ff0618bb..916ab09a24 100644
--- a/src/client/resources/ydb_ca.cpp
+++ b/src/client/resources/ydb_ca.cpp
@@ -2,10 +2,12 @@
 
 #include <ydb-cpp-sdk/client/resources/ydb_ca.h>
 
+#include <src/version.h>
+
 namespace NYdb::inline V3 {
 
 std::string GetRootCertificate() {
-    return NResource::Find("ydb_root_ca_v3.pem");
+    return NResource::Find(YDB_CERTIFICATE_FILE_KEY);
 }
 
-} // namespace NYdb
\ No newline at end of file
+} // namespace NYdb
diff --git a/src/client/resources/ydb_resources.cpp b/src/client/resources/ydb_resources.cpp
index 22a7bdd39a..ac91564718 100644
--- a/src/client/resources/ydb_resources.cpp
+++ b/src/client/resources/ydb_resources.cpp
@@ -2,6 +2,8 @@
 
 #include <ydb-cpp-sdk/client/resources/ydb_resources.h>
 
+#include <src/version.h>
+
 namespace NYdb::inline V3 {
 
 const char* YDB_AUTH_TICKET_HEADER = "x-ydb-auth-ticket";
@@ -29,7 +31,7 @@ const char* YDB_CLIENT_CAPABILITY_SESSION_BALANCER = "session-balancer";
 
 
 std::string GetSdkSemver() {
-    return NResource::Find("ydb_sdk_version_v3.txt");
+    return YDB_SDK_VERSION;
 }
 
 } // namespace NYdb
diff --git a/src/client/resources/ydb_sdk_version.txt b/src/client/resources/ydb_sdk_version.txt
deleted file mode 100644
index acf9bf09db..0000000000
--- a/src/client/resources/ydb_sdk_version.txt
+++ /dev/null
@@ -1 +0,0 @@
-3.2.2
\ No newline at end of file
diff --git a/src/client/table/table.cpp b/src/client/table/table.cpp
index 820e5ed59b..ae962207a4 100644
--- a/src/client/table/table.cpp
+++ b/src/client/table/table.cpp
@@ -2040,6 +2040,14 @@ const std::optional<std::string>& TDataQuery::GetText() const {
     return Impl_->GetText();
 }
 
+std::map<std::string, TType> TDataQuery::GetParameterTypes() const {
+    std::map<std::string, TType> typesMap;
+    for (const auto& param : Impl_->ParameterTypes_) {
+        typesMap.emplace(param.first, TType(param.second));
+    }
+    return typesMap;
+}
+
 TParamsBuilder TDataQuery::GetParamsBuilder() const {
     return TParamsBuilder(Impl_->ParameterTypes_);
 }
diff --git a/src/client/topic/impl/write_session_impl.cpp b/src/client/topic/impl/write_session_impl.cpp
index ddfb6587ca..21ea692a4d 100644
--- a/src/client/topic/impl/write_session_impl.cpp
+++ b/src/client/topic/impl/write_session_impl.cpp
@@ -951,7 +951,7 @@ void TWriteSessionImpl::OnReadDone(NYdbGrpc::TGrpcStatus&& grpcStatus, size_t co
     TProcessSrvMessageResult processResult;
     bool needSetValue = false;
     if (!grpcStatus.Ok()) {
-        errorStatus = TPlainStatus(std::move(grpcStatus));
+        errorStatus = TPlainStatus(grpcStatus);
     }
     bool doRead = false;
     {
diff --git a/src/client/topic/ut/resources/topic_A_partition_0_v24-4-2.dat b/src/client/topic/ut/resources/topic_A_partition_0_v24-4-2.dat
new file mode 100644
index 0000000000..410dfcefc0
Binary files /dev/null and b/src/client/topic/ut/resources/topic_A_partition_0_v24-4-2.dat differ
diff --git a/src/client/topic/ut/resources/topic_A_partition_1_v24-4-2.dat b/src/client/topic/ut/resources/topic_A_partition_1_v24-4-2.dat
new file mode 100644
index 0000000000..32775aa04b
Binary files /dev/null and b/src/client/topic/ut/resources/topic_A_partition_1_v24-4-2.dat differ
diff --git a/src/client/topic/ut/topic_to_table_ut.cpp b/src/client/topic/ut/topic_to_table_ut.cpp
index 50e534204c..17bf94337b 100644
--- a/src/client/topic/ut/topic_to_table_ut.cpp
+++ b/src/client/topic/ut/topic_to_table_ut.cpp
@@ -16,6 +16,7 @@
 
 #include <library/cpp/logger/stream.h>
 #include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/streams/bzip2/bzip2.h>
 
 namespace NYdb::NTopic::NTests {
 
@@ -150,6 +151,9 @@ class TFixture : public NUnitTest::TBaseFixture {
     void RestartLongTxService();
     void RestartPQTablet(const TString& topicPath, ui32 partition);
     void DumpPQTabletKeys(const TString& topicName, ui32 partition);
+    void PQTabletPrepareFromResource(const TString& topicPath,
+                                     ui32 partitionId,
+                                     const TString& resourceName);
 
     void DeleteSupportivePartition(const TString& topicName,
                                    ui32 partition);
@@ -1857,6 +1861,51 @@ void TFixture::DumpPQTabletKeys(const TString& topicName)
     }
 }
 
+void TFixture::PQTabletPrepareFromResource(const TString& topicPath,
+                                           ui32 partitionId,
+                                           const TString& resourceName)
+{
+    auto& runtime = Setup->GetRuntime();
+    TActorId edge = runtime.AllocateEdgeActor();
+    ui64 tabletId = GetTopicTabletId(edge, "/Root/" + topicPath, partitionId);
+
+    auto request = MakeHolder<TEvKeyValue::TEvRequest>();
+    size_t count = 0;
+
+    for (TStringStream stream(NResource::Find(resourceName)); true; ++count) {
+        TString key, encoded;
+
+        if (!stream.ReadTo(key, ' ')) {
+            break;
+        }
+        encoded = stream.ReadLine();
+
+        auto decoded = Base64Decode(encoded);
+        TStringInput decodedStream(decoded);
+        TBZipDecompress decompressor(&decodedStream);
+
+        auto* cmd = request->Record.AddCmdWrite();
+        cmd->SetKey(key);
+        cmd->SetValue(decompressor.ReadAll());
+    }
+
+    runtime.SendToPipe(tabletId, edge, request.Release(), 0, GetPipeConfigWithRetries());
+
+    TAutoPtr<IEventHandle> handle;
+    auto* response = runtime.GrabEdgeEvent<TEvKeyValue::TEvResponse>(handle);
+    UNIT_ASSERT(response);
+    UNIT_ASSERT(response->Record.HasStatus());
+    UNIT_ASSERT_EQUAL(response->Record.GetStatus(), NMsgBusProxy::MSTATUS_OK);
+
+    UNIT_ASSERT_VALUES_EQUAL(response->Record.WriteResultSize(), count);
+
+    for (size_t i = 0; i < response->Record.WriteResultSize(); ++i) {
+        const auto &result = response->Record.GetWriteResult(i);
+        UNIT_ASSERT(result.HasStatus());
+        UNIT_ASSERT_EQUAL(result.GetStatus(), NKikimrProto::OK);
+    }
+}
+
 void TFixture::TestTheCompletionOfATransaction(const TTransactionCompletionTestDescription& d)
 {
     for (auto& topic : d.Topics) {
@@ -3207,6 +3256,20 @@ Y_UNIT_TEST_F(Transactions_Conflict_On_SeqNo, TFixture)
     UNIT_ASSERT_VALUES_UNEQUAL(successCount, TXS_COUNT);
 }
 
+Y_UNIT_TEST_F(The_Transaction_Starts_On_One_Version_And_Ends_On_The_Other, TFixture)
+{
+    // In the test, we check the compatibility between versions `24-4-2` and `24-4-*/25-1-*`. To do this, the data
+    // obtained on the `24-4-2` version is loaded into the PQ tablets.
+
+    CreateTopic("topic_A", TEST_CONSUMER, 2);
+
+    PQTabletPrepareFromResource("topic_A", 0, "topic_A_partition_0_v24-4-2.dat");
+    PQTabletPrepareFromResource("topic_A", 1, "topic_A_partition_1_v24-4-2.dat");
+
+    RestartPQTablet("topic_A", 0);
+    RestartPQTablet("topic_A", 1);
+}
+
 }
 
 }
diff --git a/src/client/topic/ut/ut_utils/trace.h b/src/client/topic/ut/ut_utils/trace.h
index 8035e4ff80..91d11eefb8 100644
--- a/src/client/topic/ut/ut_utils/trace.h
+++ b/src/client/topic/ut/ut_utils/trace.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include "src/client/topic/common/trace_lazy.h"
+#include <src/client/topic/common/trace_lazy.h>
 
 #include "library/cpp/logger/backend.h"
 #include "library/cpp/logger/record.h"
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000000..dc5f199bd1
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace NYdb {
+
+inline const char* YDB_SDK_VERSION = "3.3.0";
+inline const char* YDB_CERTIFICATE_FILE_KEY = "ydb_root_ca_v3.pem";
+
+} // namespace NYdb
diff --git a/tests/unit/client/driver/driver_ut.cpp b/tests/unit/client/driver/driver_ut.cpp
index 46154caec7..925826cbe3 100644
--- a/tests/unit/client/driver/driver_ut.cpp
+++ b/tests/unit/client/driver/driver_ut.cpp
@@ -183,4 +183,54 @@ Y_UNIT_TEST_SUITE(CppGrpcClientSimpleTest) {
         auto session = sessionResult.GetSession();
         UNIT_ASSERT_VALUES_EQUAL(session.GetId(), "my-session-id");
     }
+
+    Y_UNIT_TEST(WithoutDiscoveryDriverLevel) {
+        TPortManager pm;
+
+        // Start our mock table service
+        TMockTableService tableService;
+        ui16 tablePort = pm.GetPort();
+        auto tableServer = StartGrpcServer(
+                TStringBuilder() << "127.0.0.1:" << tablePort,
+                tableService);
+
+        auto driver = TDriver(
+            TDriverConfig()
+                .SetEndpoint(TStringBuilder() << "localhost:" << tablePort)
+                .SetDiscoveryMode(EDiscoveryMode::Off)
+                .SetDatabase("/Root/My/DB"));
+        auto client = NTable::TTableClient(driver);
+        auto sessionFuture = client.CreateSession();
+
+        UNIT_ASSERT(sessionFuture.Wait(TDuration::Seconds(10)));
+        auto sessionResult = sessionFuture.ExtractValueSync();
+        UNIT_ASSERT(sessionResult.IsSuccess());
+        auto session = sessionResult.GetSession();
+        UNIT_ASSERT_VALUES_EQUAL(session.GetId(), "my-session-id");
+    }
+
+    Y_UNIT_TEST(WithoutDiscoveryClientLevel) {
+        TPortManager pm;
+
+        // Start our mock table service
+        TMockTableService tableService;
+        ui16 tablePort = pm.GetPort();
+        auto tableServer = StartGrpcServer(
+                TStringBuilder() << "127.0.0.1:" << tablePort,
+                tableService);
+
+        auto driver = TDriver(
+            TDriverConfig()
+                .SetEndpoint(TStringBuilder() << "localhost:" << tablePort)
+                .SetDatabase("/Root/My/DB"));
+        auto client = NTable::TTableClient(driver, TClientSettings().DiscoveryMode(EDiscoveryMode::Off));
+        auto sessionFuture = client.CreateSession();
+
+        UNIT_ASSERT(sessionFuture.Wait(TDuration::Seconds(10)));
+        auto sessionResult = sessionFuture.ExtractValueSync();
+        UNIT_ASSERT(sessionResult.IsSuccess());
+        auto session = sessionResult.GetSession();
+        UNIT_ASSERT_VALUES_EQUAL(session.GetId(), "my-session-id");
+    }
+
 }